Re: Address of a class object
On Thursday, 5 January 2023 at 04:04:39 UTC, Paul wrote: .. Do I have this much right? ... First, i would say, add @safe to your main. @safe void main() ... Then you will see you are treading on dangerous waters ;-) Second, to be sure your getting the correct results, it would be nice if there was a 'category of type' in std.traits for: isAllocatedOnStack isAllocatedOnHeap As it is, your just guessing (although the addresses printed will clear this up for you anyway I guess). Also, I cannot read hex, so if it were me, I'd be casting the hex into an size_t: cast(size_t)&MyInt
Re: Address of a class object
On 1/4/23 20:04, Paul wrote: >> (Again, there is no problem here; we are just learning.) >> Ali > > Do I have this much right? > ..with this output? Looks good to me. While we're here, you can force the class objects to be on the stack as well: scope MyClassVar1 = new MyClass(); I replaced 'auto' with 'scope'. Ali
Re: Address of a class object
(Again, there is no problem here; we are just learning.) Ali Do I have this much right? ```d import std.stdio, std.traits; class MyClass {char c;} void main() { auto MyInt = 1; writeln("The address of MyInt is : ",&MyInt," (stack)"); auto MyClassVar1 = new MyClass(); writeln("The address of MyClassVar1 is: ",&MyClassVar1," (stack)"); auto MyClassVar2 = new MyClass(); writeln("The address of MyClassVar2 is: ",&MyClassVar2," (stack)"); writeln; auto MyClassObj1 = cast(void*)MyClassVar1; writeln("The address of MyClassObj1 is: ",MyClassObj1," (heap)"); auto MyClassObj2 = cast(void*)MyClassVar2; writeln("The address of MyClassObj2 is: ",MyClassObj2," (heap)"); } ``` ..with this output? ``` The address of MyInt is : 1CA1CFFB1C (stack) The address of MyClassVar1 is: 1CA1CFFB10 (stack) The address of MyClassVar2 is: 1CA1CFFB08 (stack) The address of MyClassObj1 is: 1EB93212000 (heap) The address of MyClassObj2 is: 1EB93212020 (heap) ```
Re: Is there a way to enforce UFCS?
On Wednesday, 4 January 2023 at 14:21:46 UTC, bauss wrote: On Wednesday, 4 January 2023 at 03:42:28 UTC, thebluepandabear wrote: ... My question is: is there a way to enforce UFCS-syntax? None of your code actually uses UFCS. This is UFCS: ``` class Foo { int bar; } void setBar(Foo foo, int value) { foo.bar = value; } void main() { foo.setBar(100); // UFCS setBar(foo, 100); // Non-UFCS (Above expands to this) } ``` This is not UFCS but just class method calling: ``` class Foo { int bar; void setBar(Foo foo, int value) { foo.bar = value; } } void main() { foo.setBar(100); // Not UFCS - just method call to the class foo.setBar = 100; // Not UFCS - simply a setter function call (equal to the above) setBar(foo, 100); // Error } ``` Also note that @property doesn't really do anything now and there's even talk about deprecating it. Althought I personally still use it, then it doesn't have much of a function and none of your code is affected if you remove it. Yeah I got mixed up. I think a good use of `@property` is for code clarity, it makes it clear which parts of your code should be treated as properties.
Re: Address of a class object
On 1/4/23 13:43, H. S. Teoh wrote: > You do realize that the compiler is free to reorder local variables on > the stack, right? ;-) Of course. :) I was trying different strategies to catch the compiler (dmd here) in a single act of 8-byte object alignment as reported by .alignof. Another thing the compiler is free for class members is to reorder them. I also theorized perhaps the compiler was also considering the alignment of a member. But as expected, char[1] does have 1 alignment and it can't be the reason in this case. (Again, there is no problem here; we are just learning.) > implementation-specific details RazvanN or Dennis may chime in on that. Ali
Re: Address of a class object
On Wed, Jan 04, 2023 at 01:20:12PM -0800, Ali Çehreli via Digitalmars-d-learn wrote: > On 1/4/23 12:02, Steven Schveighoffer wrote: > > On 1/4/23 2:27 PM, Ali Çehreli wrote: > > >> I put the objects into a 2-length > >> static array but the difference was still 0x20. (?) > > > > Are you putting the class *references* in a 2-length static array? > > I lied. As I could not put the objects in a static array, I put them > on the stack with the 'scope' keyword and the difference was still > 0x20. (Of course, I could emplace the objects myself in my static > array but that wouldn't prove anything about why the current alignment > appears to be 0x20.) You do realize that the compiler is free to reorder local variables on the stack, right? ;-) Generally it doesn't, but nothing in the spec precludes it from doing so. Highly-optimizing compilers like ldc also tend to move code around, and with it, any associated local variables, so exactly where something is put on the stack isn't really something you can rely on. And of course, stuff on the stack may also be subject to alignment requirements depending on your CPU/architecture. Though generally speaking this shouldn't be any stricter than alignment requirements on general heap/GC allocations. > > stop worrying about the addresses given out by the GC > > No worries; just trying to explain... [...] I think at this point any explanation is likely to involve many more implementation-specific details than is warranted for understanding D code. :-P It can of course be extremely interesting (and instructive) to know about these details, but one has to keep in mind that the deeper one digs, the more non-portable these implementation details become, and the more divergences you'll see across different CPUs and OSes. T -- Insanity is doing the same thing over and over again and expecting different results.
Re: Address of a class object
On 1/4/23 12:02, Steven Schveighoffer wrote: > On 1/4/23 2:27 PM, Ali Çehreli wrote: >> I put the objects into a 2-length >> static array but the difference was still 0x20. (?) > > Are you putting the class *references* in a 2-length static array? I lied. As I could not put the objects in a static array, I put them on the stack with the 'scope' keyword and the difference was still 0x20. (Of course, I could emplace the objects myself in my static array but that wouldn't prove anything about why the current alignment appears to be 0x20.) > stop worrying about the addresses > given out by the GC No worries; just trying to explain... Ali
Re: Address of a class object
On 1/4/23 2:27 PM, Ali Çehreli wrote: On 1/4/23 10:48, H. S. Teoh wrote: > Allocations are not necessarily consecutive; the GC may have its own > strategy of allocation that doesn't follow a linear sequence. That was one of my guesses. So, I put the objects into a 2-length static array but the difference was still 0x20. (?) Are you putting the class *references* in a 2-length static array? That's just going to be 2 pointers in an array, and won't affect where they are allocated on the heap. > Furthermore, GC-allocated blocks may be larger than the request size > because there may be some extra management information stored in the > block (but outside the pointer range returned). Good point. I think the minimum size of a dynamically allocated memory of the current GC implementation is 32 bytes. It is 16 bytes, but there are no 24-byte bins. Here are the bin sizes: https://github.com/dlang/dmd/blob/4dc7259a89950b0a0feda05b8c35e52cadd00c95/druntime/src/core/internal/gc/impl/conservative/gc.d#L1402-L1424 And of course, this could change again. Basically, follow H. S. Teoh's advice, stop worrying about the addresses given out by the GC, it's not important. -Steve
Re: Address of a class object
On 1/4/23 11:27, Ali Çehreli wrote: > writeln("hidden 0: ", hiddenValue(addr, 0)); > writeln("hidden 1: ", hiddenValue(addr, 1)); Silly me! :) Those members have names: writeln("__vptr : ", obj.__vptr); writeln("__monitor : ", obj.__monitor); https://dlang.org/spec/abi.html#classes Ali
Re: Address of a class object
On 1/4/23 10:48, H. S. Teoh wrote: > Allocations are not necessarily consecutive; the GC may have its own > strategy of allocation that doesn't follow a linear sequence. That was one of my guesses. So, I put the objects into a 2-length static array but the difference was still 0x20. (?) > Furthermore, GC-allocated blocks may be larger than the request size > because there may be some extra management information stored in the > block (but outside the pointer range returned). Good point. I think the minimum size of a dynamically allocated memory of the current GC implementation is 32 bytes. I've just realized that I was confusing myself by thinking the object pointer that cast(void*) produces was the first member's address. I was wrong: That is the address of the first of the two hidden members (the vtbl pointer and the monitor). My current guess is, although it could be a void*, the alignment of the first of those hidden members is 16. Now that I have a more correct understanding, the following program prints those hidden members. One of the examples shows the monitor of an object used with 'synchronized' is non-null. import std.stdio, std.traits; class MyClass { char[1] c; } void main() { writeln(" Size Alignment Type\n", "="); size_t size = __traits(classInstanceSize, MyClass); size_t alignment = classInstanceAlignment!MyClass; writefln("%4s%8s %s",size, alignment, MyClass.stringof); // Apologies for using lower-cased variable names. :) auto a = new MyClass(); auto b = new MyClass(); printObject!a; printObject!b; auto withMonitor = new MyClass(); synchronized (withMonitor) { // This object's "hidden 1" (the monitor) will not be 'null' printObject!withMonitor; } // This object's "hidden 0" (vtbl pointer) will be different: class SubClass : MyClass { } auto sub = new SubClass(); printObject!sub; } void printObject(alias obj)() { writeln("\n"); writeln("name: ", obj.stringof); const addr = cast(void*)obj; writeln("address : ", addr); writeln("hidden 0: ", hiddenValue(addr, 0)); writeln("hidden 1: ", hiddenValue(addr, 1)); } void* hiddenValue(const(void)* obj, size_t index) { alias HiddenType = void*; auto ptrToHiddens = cast(HiddenType[2]*)obj; return (*ptrToHiddens)[index]; } Here is the output: Size Alignment Type = 17 8 MyClass name: a address : 7F4009D48000 hidden 0: 558A1E172520 hidden 1: null name: b address : 7F4009D48020 hidden 0: 558A1E172520 hidden 1: null name: withMonitor address : 7F4009D48040 hidden 0: 558A1E172520 hidden 1: 558A20164B80 <-- non-null monitor name: sub address : 7F4009D48060 hidden 0: 558A1E172630 <-- Different vtbl for sub-class hidden 1: null Ali
Re: Address of a class object
On Wed, Jan 04, 2023 at 09:51:05AM -0800, Ali Çehreli via Digitalmars-d-learn wrote: > On 1/3/23 20:01, Paul wrote: > > > Size Alignment Type > > = > >17 8 MyClass > > > > MyClassObj1 MyClassObj2 > > 27727202000 27727202020 > > ``` > > If my size is 17 bytes and my alignment is 8 bytes, shouldn't my > > MyClassObj2 in this example be @ 277272020**18** ? > > Good question. > > I made some guesses about object layouts, GC allocation schemes, etc. > but did not like any of them. [...] Allocations are not necessarily consecutive; the GC may have its own strategy of allocation that doesn't follow a linear sequence. Furthermore, GC-allocated blocks may be larger than the request size because there may be some extra management information stored in the block (but outside the pointer range returned). Basically, addresses returned by an allocator (GC or otherwise) should be treated as opaque handles, whose exact values are implementation- dependent and not really relevant to application code other than identifying the allocated object. T -- We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare. Now, thanks to the Internet, we know this is not true. -- Robert Wilensk
Re: Address of a class object
On 1/3/23 20:01, Paul wrote: > Size Alignment Type > = >17 8 MyClass > > MyClassObj1 MyClassObj2 > 27727202000 27727202020 > ``` > If my size is 17 bytes and my alignment is 8 bytes, shouldn't my > MyClassObj2 in this example be @ 277272020**18** ? Good question. I made some guesses about object layouts, GC allocation schemes, etc. but did not like any of them. Ali
Re: Is there a way to enforce UFCS?
On Wednesday, 4 January 2023 at 03:42:28 UTC, thebluepandabear wrote: ... My question is: is there a way to enforce UFCS-syntax? None of your code actually uses UFCS. This is UFCS: ``` class Foo { int bar; } void setBar(Foo foo, int value) { foo.bar = value; } void main() { foo.setBar(100); // UFCS setBar(foo, 100); // Non-UFCS (Above expands to this) } ``` This is not UFCS but just class method calling: ``` class Foo { int bar; void setBar(Foo foo, int value) { foo.bar = value; } } void main() { foo.setBar(100); // Not UFCS - just method call to the class foo.setBar = 100; // Not UFCS - simply a setter function call (equal to the above) setBar(foo, 100); // Error } ``` Also note that @property doesn't really do anything now and there's even talk about deprecating it. Althought I personally still use it, then it doesn't have much of a function and none of your code is affected if you remove it.