www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - D vs. placement new (for classes) aka why D needs .sizeof and .alignof for classes (values not references)

reply Forest Ray <disto flying-guillotine.com> writes:
Before I add this to the bug database I wanted to run this by everyone and see
if I'm overlooking something.  Classes in D are always a reference.  Therefore
the .sizeof and .alignof a class (reference) are always (void*).sizeof and
(void*).alignof.  D allows the class allocator (new) to be overloaded.  The
number of bytes required to hold the class (value) is passed as the first
parameter to new(size_t size).  This works well unless you are wanting to
perform a placement new.  When using placement new you pass in the storage for
the object to be placed.  

new(size_t size, void* ptr) {
    return ptr;
}

The problem is at compile time you can NOT determine the size or alignment of a
class (value), only the reference.  Therefore you can not know the sizeof the
buffer to preallocate to hold the class (value).  I believe this to be an
oversight in the language design.  The alignment issue is easier to overcome,
the ABI states the first field of a class (value) is the vbtbl pointer which
will always mean the class (value) is (void*).alignof aligned.  The .sizeof
property for a class (value) is not available, here in lies the problem. 
Placement new is the easy example where the sizeof the class (value) is needed.
 Also consider the case of a blocks of class (values) being preallocated for a
free list.
Apr 12 2007
next sibling parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Forest Ray wrote:
 Before I add this to the bug database I wanted to run this by everyone and see
if I'm overlooking something.  Classes in D are always a reference.  Therefore
the .sizeof and .alignof a class (reference) are always (void*).sizeof and
(void*).alignof.  D allows the class allocator (new) to be overloaded.  The
number of bytes required to hold the class (value) is passed as the first
parameter to new(size_t size).  This works well unless you are wanting to
perform a placement new.  When using placement new you pass in the storage for
the object to be placed.  
 
 new(size_t size, void* ptr) {
     return ptr;
 }
 
 The problem is at compile time you can NOT determine the size or alignment of
a class (value), only the reference.  Therefore you can not know the sizeof the
buffer to preallocate to hold the class (value).  I believe this to be an
oversight in the language design.  The alignment issue is easier to overcome,
the ABI states the first field of a class (value) is the vbtbl pointer which
will always mean the class (value) is (void*).alignof aligned.  The .sizeof
property for a class (value) is not available, here in lies the problem. 
Placement new is the easy example where the sizeof the class (value) is needed.
 Also consider the case of a blocks of class (values) being preallocated for a
free list.
 
Given: class Foo { ... } auto obj = new Foo; There is: obj.sizeof Which you know, and does as you say. But then there is: obj.classinfo.init.sizeof Which will render the actual size of class instances. :) Granted it isn't very pretty, but it works. What _would_ be nifty, would be if one could use 'Foo.sizeof' (invoke .sizeof on the type rather than the variable) to get the same value. Ie, make Class.sizeof an alias to Class.classinfo.init.sizeof -- I don't think this would be a problem. In the meantime, the .classinfo trick is your friend. -- Chris Nicholson-Sauls
Apr 12 2007
parent reply "Frank Benoit (keinfarbton)" <benoit tionex.removethispart.de> writes:
 Which you know, and does as you say.  But then there is:
 obj.classinfo.init.sizeof
 
 Which will render the actual size of class instances.  :)
no, it doesn't :)
Apr 12 2007
next sibling parent reply torhu <fake address.dude> writes:
Frank Benoit (keinfarbton) wrote:
 Which you know, and does as you say.  But then there is:
 obj.classinfo.init.sizeof
 
 Which will render the actual size of class instances.  :)
no, it doesn't :)
obj.classinfo.init.length is documented as 'init.length gives size in bytes of class'.
Apr 12 2007
parent reply "Frank Benoit (keinfarbton)" <benoit tionex.removethispart.de> writes:
torhu schrieb:
 Frank Benoit (keinfarbton) wrote:
 Which you know, and does as you say.  But then there is:
 obj.classinfo.init.sizeof

 Which will render the actual size of class instances.  :)
no, it doesn't :)
obj.classinfo.init.length is documented as 'init.length gives size in bytes of class'.
well, i don't know about the size of the class, but it does not give the size of the class /instance/.
Apr 12 2007
parent reply "Frank Benoit (keinfarbton)" <benoit tionex.removethispart.de> writes:
 well, i don't know about the size of the class, but it does not give the
 size of the class /instance/.
I was sure i had an example that shows it doesn't. But it seems I am wrong. Sorry about that. If i find it, I file a bug report. Frank
Apr 12 2007
parent reply Forest Ray <disto flying-guillotine.com> writes:
Thanks for get me thinking along that path, the size of a class can be found by
using CLASS.classinfo.init.length

import std.stdio;

class foo {
	int a = 1;
	int b = 2;
	int c = 3;
}

void main() {
	writefln("size = ", foo.classinfo.init.length);
}

./xxx
size = 20


Frank Benoit (keinfarbton) Wrote:

 
 well, i don't know about the size of the class, but it does not give the
 size of the class /instance/.
I was sure i had an example that shows it doesn't. But it seems I am wrong. Sorry about that. If i find it, I file a bug report. Frank
Apr 12 2007
parent "Frank Benoit (keinfarbton)" <benoit tionex.removethispart.de> writes:
Finally i found my testcase...
it does not work on linux.
See http://d.puremagic.com/issues/show_bug.cgi?id=1141
Apr 13 2007
prev sibling parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Frank Benoit (keinfarbton) wrote:
 Which you know, and does as you say.  But then there is:
 obj.classinfo.init.sizeof

 Which will render the actual size of class instances.  :)
no, it doesn't :)
Note to self: sleep|eat|veg first, post later. Ah well, at least the correct property got brought up eventually. I'll just go punish myself now (ie, go to bed). :) -- Chris Nicholson-Sauls
Apr 12 2007
prev sibling next sibling parent reply Sean Kelly <sean f4.ca> writes:
Forest Ray wrote:
 Before I add this to the bug database I wanted to run this
 by everyone and see if I'm overlooking something.  Classes
 in D are always a reference.  Therefore the .sizeof and
 .alignof a class (reference) are always (void*).sizeof and
 (void*).alignof.  D allows the class allocator (new) to be
 overloaded.  The number of bytes required to hold the class
 (value) is passed as the first parameter to new(size_t size).
 This works well unless you are wanting to perform a placement
 new.  When using placement new you pass in the storage for
 the object to be placed.

 
 new(size_t size, void* ptr) {
     return ptr;
 }
 
 The problem is at compile time you can NOT determine the
 size or alignment of a class (value), only the reference.
 Therefore you can not know the sizeof the buffer to
 preallocate to hold the class (value).  I believe this to be
 an oversight in the language design.  The alignment issue is
 easier to overcome, the ABI states the first field of a
 class (value) is the vbtbl pointer which will always mean
 the class (value) is (void*).alignof aligned.  The .sizeof
 property for a class (value) is not available, here in lies
 the problem.  Placement new is the easy example where the
 sizeof the class (value) is needed.  Also consider the case
 of a blocks of class (values) being preallocated for a free list.
See http://d.puremagic.com/issues/show_bug.cgi?id=88 Sean
Apr 12 2007
parent reply Dan <murpsoft hotmail.com> writes:
I love D, one of the reasons being because Walter has provided unprecedented
flexibility for structs; giving us almost all the features of classes without
their drawbacks.

structs have operator overloading and methods.  : D

structs now only lack constructors, destructors, inheritance, interfaces, and
private members (encapsulation).

I agree that constructors, destructors and interfaces are useful features...
moving on;

~~
Inheritance:

Inheritance is something I tend to disagree with because: if one examines a
class inheriting from another, there is no indication of the presence of
inherited properties or methods within it's declaration other than the ':
superClass' at the top.  Upon examining the superClass, you may then have to
examine it's superClass and so forth; so finding out what members a class may
have can take examining a dozen files.  This is the intended modus operandi.

I argue the better methodology is to implement interfaces, and architect the
code such that few - if any - features are ever duplicated.  If need be,
implementing a template is also an option.

Sure aristotle found that many things exhibit the same features and methods, I
argue that redundancy is counter-productive to efficient algorithm execution;
having no reflection on whether cats have fur and dogs do too.

~~
Encapsulation:

Oddly, Java Programmers(tm) tend to think that encapsulating a property and
providing a simple getter and setter for it is somehow a good thing.  I argue
that you're cluttering your NS with redundant information, and causing your
code to jump into the getter and setter method every time you access a property
without adding anything useful.

In open source programming, the only reason I can find to encapsulate is to
provide a clearly defined external interface to allow implementation changes
without affecting the implemented interface; i.e: allowing programmers to see
into the box might lead one to take advantage of it's bugs.  Again, the
usefulness of interfaces makes itself clear.

~~
Drawbacks of Classes:

Classes lack transparency.  You don't know the size, the location, the
alignment... there is code and structure within them you aren't aware of, and
much of it is often unneccassary.  You cannot intelligently manipulate the
implementation of a class even internally - such as iterating through an array
of them and accessing a property simply by adding the sizeof to an iterator.

You cannot pass a class by value, while a struct can be passed by value or
reference.  You cannot easily duplicate an Object instanciated from a class. 
You cannot declare an instanciated Object literal, but you can declare such a
struct.

These shortcomings I feel are sufficient to warrant the use of structs unless
you are implementing an interface which other programmers will use in their own
code (read: library), or getters/setters/ctor/dtor are critical to the legible
implementation of something such that a good-old-fashioned method on the struct
won't do.

I'm looking forward to any replies.  
I want to learn any reasons why I might be wrong?
Apr 13 2007
parent reply Sean Kelly <sean f4.ca> writes:
Dan wrote:
 Inheritance:
 
 Inheritance is something I tend to disagree with
...
 I argue the better methodology is to implement interfaces
Funny. I just finished "Prefactoring" by Ken Pugh, and he seems to feel the same way. One reason seemed to be that it's easier to add or change interface compliance than it is to restructure an inheritance hierarchy. And for implementation sharing, it's often just as easy to abstract the common bits into support objects.
 Encapsulation:
 
 Oddly, Java Programmers(tm) tend to think that encapsulating a
 property and providing a simple getter and setter for it is somehow
 a good thing.  I argue that you're cluttering your NS with redundant
 information, and causing your code to jump into the getter and setter
 method every time you access a property without adding anything useful.
The argument for Java is that if everything is abstracted through get/set methods then there is a common point of analysis for debugging and it is painless to add additional functionality, change implementation, etc. Since D has property syntax however, the argument for starting out with everything hidden behind get/set methods is a bit weaker. If you have public data and later decide to hide it behind get/set methods, you can often do so without changing syntax from a user end. I don't think efficiency is an issue however. Get/set methods are almost always inlined, so there should be no performance penalty.
 Drawbacks of Classes:
 
 Classes lack transparency.  You don't know the size, the location,
 the alignment... there is code and structure within them you aren't
 aware of, and much of it is often unneccassary.  You cannot
 intelligently manipulate the implementation of a class even internally
 - such as iterating through an array of them and accessing a property
 simply by adding the sizeof to an iterator.
I'm not sure it's really as bad as all that. Knowing class instance size at compile-time would be useful for some storage methods, but data order and such shouldn't be an issue. However, the .tupleof property implies that class data will typically be stored in declaration order anyway, since to do otherwise would complicate things unnecessarily.
 You cannot pass a class by value, while a struct can be passed by
 value or reference.  You cannot easily duplicate an Object instanciated
 from a class.  You cannot declare an instanciated Object literal, but
 you can declare such a struct.
Personally, I think it's actually a good thing that classes can't be passed by value. It's a bit of a change from C++, but it dramatically simplifies some things that are difficult to impossible in C++. For example, one idea being discussed for multithreaded C++ 0x is to pass uncaught exceptions to the joining thread. Because exceptions are typically allocated on the stack and thrown via copying, this is not at all easy, but in D I was able to implement this in about five minutes.
 These shortcomings I feel are sufficient to warrant the use of
 structs unless you are implementing an interface which other
 programmers will use in their own code (read: library), or
 getters/setters/ctor/dtor are critical to the legible implementation
 of something such that a good-old-fashioned method on the struct
 won't do.
Without copy semantics (which I'm not sure structs should have), the use of structs is somewhat limited in D. For the most part, I think they really are best as aggregates. But this difference between classes and structs is good justification for both to exist in the language. Sean
Apr 13 2007
parent reply "David B. Held" <dheld codelogicconsulting.com> writes:
Sean Kelly wrote:
 Dan wrote:
 [...]
 Inheritance is something I tend to disagree with...
 I argue the better methodology is to implement interfaces
Funny. I just finished "Prefactoring" by Ken Pugh, and he seems to feel the same way. One reason seemed to be that it's easier to add or change interface compliance than it is to restructure an inheritance hierarchy. And for implementation sharing, it's often just as easy to abstract the common bits into support objects.
I agree that inheritance is generally overused, and even Bjarne has lamented this fact. He originally designed abstract base classes as a way to implement interfaces in C++ with the intention that most inheritance would be of such ABCs, but was quite dismayed when people mostly ignored the mechanism and proceeded to derive every class in sight. He might as well have thrown in std::Object. Thus, interfaces should definitely be preferred where possible. That being said, many idioms and design patterns are not possible without outright inheritance, like CRTP and Policy-Based Design. There is a rightful place for both.
 Encapsulation:
 [...]
The problem with Java-style "encapsulation" is not that it's redundant, but that it's not encapsulation. The presence of an explicit setter is almost always an indication of a design flaw. The exception to this principle are frameworks that are heavily and explicitly stateful, such as GUIs. In this case, I think setters are just fine, but you will often find that they are more than a trivial assignment, also. In good encapsulation, accessors give you readonly visibility, while mutators are carefully constructed to only provide the types of state change that are necessary for the object, rather than the arbitrary and random mutation that explicit setters allow. This is primarily because mutators need to preserve class invariants, which is either harder or less efficient to do with arbitrary setters.
 Drawbacks of Classes:

 Classes lack transparency.  You don't know the size, the location,
 the alignment... there is code and structure within them you aren't
 aware of, and much of it is often unneccassary.  You cannot
 intelligently manipulate the implementation of a class even internally
 - such as iterating through an array of them and accessing a property
 simply by adding the sizeof to an iterator.
Classes are supposed to lack transparency. That's the point of abstraction. ;) The benefit of classes is runtime dispatch. If you are willing to pay for that, you are usually not concerned with the alignment and other low-level details. Accessing a class by directly addressing its internals is a fairly unsound thing to do. Allowing users to do that would make it pointless to have access modifiers. If you really need to do something like that, you should be able to use a disassembly to see how the class is laid out. I think that's a perfectly reasonable requirement for doing something as non-portable and intrusive as that.
 [...]
 You cannot pass a class by value, while a struct can be passed by
 value or reference.  You cannot easily duplicate an Object instanciated
 from a class.  You cannot declare an instanciated Object literal, but
 you can declare such a struct.
[...]
The benefit of passing entities by value is efficiency, because copying the value is relatively cheap. However, classes are already bigger than structs, and most classes of interesting size would be fairly expensive to copy around as values. Cloning an object is not something that everyone wants to do, but implementing it is fairly straightforward. I'm not seeing the big drawback here. Struct literals make sense because they are intended to be used as value types. Classes are not intended to be used as value types, so there is a much less compelling argument for allowing Class literals.
 These shortcomings I feel are sufficient to warrant the use of
 structs unless you are implementing an interface which other
 programmers will use in their own code (read: library), or
 getters/setters/ctor/dtor are critical to the legible implementation
 of something such that a good-old-fashioned method on the struct
 won't do.
Without copy semantics (which I'm not sure structs should have), the use of structs is somewhat limited in D. For the most part, I think they really are best as aggregates. But this difference between classes and structs is good justification for both to exist in the language.
I think structs should have copy semantics, personally; but that's another story. I think a good design practice is to use value types (immutable structs) wherever possible and free functions. After all, this is the essence of functional programming (or part of it, anyway), which has many benefits to recommend it. On the other hand, this doesn't work so well with highly mutable systems like GUIs and DBs, which tend to be the workhorses of industry and probably comprise a fair portion of D's market segment. Dave
Apr 14 2007
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
David B. Held wrote:
 Sean Kelly wrote:
 Dan wrote:
 [...]
 Inheritance is something I tend to disagree with...
 I argue the better methodology is to implement interfaces
Funny. I just finished "Prefactoring" by Ken Pugh, and he seems to feel the same way. One reason seemed to be that it's easier to add or change interface compliance than it is to restructure an inheritance hierarchy. And for implementation sharing, it's often just as easy to abstract the common bits into support objects.
I agree that inheritance is generally overused, and even Bjarne has lamented this fact. He originally designed abstract base classes as a way to implement interfaces in C++ with the intention that most inheritance would be of such ABCs, but was quite dismayed when people mostly ignored the mechanism and proceeded to derive every class in sight. He might as well have thrown in std::Object. Thus, interfaces should definitely be preferred where possible. That being said, many idioms and design patterns are not possible without outright inheritance, like CRTP and Policy-Based Design. There is a rightful place for both.
 Encapsulation:
 [...]
The problem with Java-style "encapsulation" is not that it's redundant, but that it's not encapsulation. The presence of an explicit setter is almost always an indication of a design flaw. The exception to this principle are frameworks that are heavily and explicitly stateful, such as GUIs. In this case, I think setters are just fine, but you will often find that they are more than a trivial assignment, also. In good encapsulation, accessors give you readonly visibility, while mutators are carefully constructed to only provide the types of state change that are necessary for the object, rather than the arbitrary and random mutation that explicit setters allow. This is primarily because mutators need to preserve class invariants, which is either harder or less efficient to do with arbitrary setters.
 Drawbacks of Classes:

 Classes lack transparency.  You don't know the size, the location,
 the alignment... there is code and structure within them you aren't
 aware of, and much of it is often unneccassary.  You cannot
 intelligently manipulate the implementation of a class even internally
 - such as iterating through an array of them and accessing a property
 simply by adding the sizeof to an iterator.
Classes are supposed to lack transparency. That's the point of abstraction. ;) The benefit of classes is runtime dispatch. If you are willing to pay for that, you are usually not concerned with the alignment and other low-level details. Accessing a class by directly addressing its internals is a fairly unsound thing to do. Allowing users to do that would make it pointless to have access modifiers. If you really need to do something like that, you should be able to use a disassembly to see how the class is laid out. I think that's a perfectly reasonable requirement for doing something as non-portable and intrusive as that.
 [...]
 You cannot pass a class by value, while a struct can be passed by
 value or reference.  You cannot easily duplicate an Object instanciated
 from a class.  You cannot declare an instanciated Object literal, but
 you can declare such a struct.
[...]
The benefit of passing entities by value is efficiency, because copying the value is relatively cheap. However, classes are already bigger than structs, and most classes of interesting size would be fairly expensive to copy around as values. Cloning an object is not something that everyone wants to do, but implementing it is fairly straightforward. I'm not seeing the big drawback here. Struct literals make sense because they are intended to be used as value types. Classes are not intended to be used as value types, so there is a much less compelling argument for allowing Class literals.
Uhm... except that we have them already? Or is this not what you meant: -- Chris Nicholson-Sauls
Apr 14 2007
parent reply "David B. Held" <dheld codelogicconsulting.com> writes:
Chris Nicholson-Sauls wrote:
 [...]
 Uhm... except that we have them already?  Or is this not what you meant:
 







Hmm...that's pretty cool. I guess that is needed for Java compatibility, huh? Dave
Apr 14 2007
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
David B. Held wrote:
 Chris Nicholson-Sauls wrote:
 [...]
 Uhm... except that we have them already?  Or is this not what you meant:








Hmm...that's pretty cool. I guess that is needed for Java compatibility, huh? Dave
I assume that's why we got them. I really don't remember what justification Walter gave for them at the time, but it was probably a requested thing. Although honestly, the one thing I used this often for in Java was event handlers... and in D we have the oh-so-beautiful delegates to do that sort of thing. Plus the three or so Signals/Slots implementations floating around, which are also beautiful. So I have trouble thinking of any really compelling use for anonymous objects. -- Chris Nicholson-Sauls
Apr 15 2007
parent Dan <murpsoft hotmail.com> writes:
Chris Nicholson-Sauls Wrote:
 implementations floating around, which are also beautiful.  So I have trouble
thinking of 
 any really compelling use for anonymous objects.
I don't, if one wanted everything to be class-oriented. An associative array of Objects implementing the same interface differently, for example...
Apr 15 2007
prev sibling parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Forest Ray wrote:
 Before I add this to the bug database I wanted to run this by everyone and see
if I'm overlooking something.  Classes in D are always a reference.  Therefore
the .sizeof and .alignof a class (reference) are always (void*).sizeof and
(void*).alignof.  D allows the class allocator (new) to be overloaded.  The
number of bytes required to hold the class (value) is passed as the first
parameter to new(size_t size).  This works well unless you are wanting to
perform a placement new.  When using placement new you pass in the storage for
the object to be placed.  
 
 new(size_t size, void* ptr) {
     return ptr;
 }
 
 The problem is at compile time you can NOT determine the size or alignment of
a class (value), only the reference.  Therefore you can not know the sizeof the
buffer to preallocate to hold the class (value).  I believe this to be an
oversight in the language design.  The alignment issue is easier to overcome,
the ABI states the first field of a class (value) is the vbtbl pointer which
will always mean the class (value) is (void*).alignof aligned.  The .sizeof
property for a class (value) is not available, here in lies the problem. 
Placement new is the easy example where the sizeof the class (value) is needed.
 Also consider the case of a blocks of class (values) being preallocated for a
free list.
OH but you CAN! It took me a while to work this out, and I must admit that I have *not* tested the code in some time. That said, it should still work. In a nutshell, here's how it works: given a class type, you can deduce the size of an instance at compile time by finding the maximum of (offset+size) for each member variable of the class. If the class has no members, then use 2*(void*).sizeof, to account for the ClassInfo and vtbl pointers. You also need to add in some padding for any additional interfaces. Finally, you take the maximum of that and the size of the super class (if any). It's messy, and it was largely arrived at by "define a whole bunch of classes and fudge it until it's right", but I've used it in two custom allocators and never had a problem. FYI, I release the below code into the public domain: share and enjoy! -- Daniel ----- module etc.mem.util; private struct Align { ubyte a; void* b; } private const PTR_ALIGN = Align.tupleof[1].alignof; version( X86 ) const MEM_ALIGN = 8u; else static assert(false, "Unknown memory alignment for this platform."); private template AlignPad(size_t base, size_t aligned) { static if( aligned == 0 ) const AlignPad = base; else const AlignPad = ((base+PTR_ALIGN-1)/PTR_ALIGN)*PTR_ALIGN + aligned; } template InstanceSize(T) { static if( is( T == Object ) ) const InstanceSize = 2*(void*).sizeof; else const InstanceSize = Max!( AlignPad!( InstanceSize!(Super!(T)), InterfaceCount!(T)*(void*).sizeof), AlignPad!( InstanceSizeImpl!(T, 0), + InterfaceCount!(T)*(void*).sizeof)); } private template Super(T) { static if( is( T S == super ) ) alias First!(S) Super; else static assert(false, "Can't get super of "~T.mangleof); } private template First(T) { alias T First; } private template First(T, Ts...) { alias T First; } private template InstanceSizeImpl(T, size_t i) { static if( i < T.tupleof.length ) const InstanceSizeImpl = Max!( T.tupleof[i].offsetof + T.tupleof[i].sizeof, InstanceSizeImpl!(T, i+1)); else // This is necessary to account for classes without member // variables. const InstanceSizeImpl = 2*(void*).sizeof; } private template Max(size_t a, size_t b) { static if( a > b ) const Max = a; else const Max = b; } template InstanceSizeAligned(T, size_t alignment=MEM_ALIGN) { static if( alignment == 0 ) const InstanceSizeAligned = InstanceSize!(T); else const uint InstanceSizeAligned = InstanceSizeAlignImpl!(T, alignment).result; } private template InstanceSizeAlignedImpl(T, size_t alignment) { private const base_size = InstanceSize!(T); const result = ((base_size+alignment-1)/alignment)*alignment; } private template InterfaceCount(T) { static if( is( T == Object ) ) const InterfaceCount = 0u; else static if( is( T S == super ) ) const InterfaceCount = InterfaceCountImpl!(S); } private template InterfaceCountImpl(TBase, TInterfaces...) { const InterfaceCountImpl = TInterfaces.length; } version( etc_mem_util_main ) { import std.stdio; interface I1 { } interface I2 { } interface I3 : I2 { } class A { } class B : A, I1 { } class C : B { ubyte x; real y; } class D : C, I3 { } class E : D, I3 { } template SuperTuple(T) { static if( is( T S == super ) ) alias S SuperTuple; } void main() { writefln("A: %s; %d, %d", typeid(SuperTuple!(A)), A.classinfo.init.length, InstanceSize!(A)); writefln("B: %s; %d, %d", typeid(SuperTuple!(B)), B.classinfo.init.length, InstanceSize!(B)); writefln("C: %s; %d, %d", typeid(SuperTuple!(C)), C.classinfo.init.length, InstanceSize!(C)); writefln("D: %s; %d, %d", typeid(SuperTuple!(D)), D.classinfo.init.length, InstanceSize!(D)); writefln("E: %s; %d, %d", typeid(SuperTuple!(E)), E.classinfo.init.length, InstanceSize!(E)); writefln("InterfaceCount!(E) == %d", InterfaceCount!(E)); writefln("ptr alignment: %d", Align.tupleof[1].alignof); } } -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
Apr 16 2007
parent reply Dan <murpsoft hotmail.com> writes:
Okay, so my summary so far:

- having the ability to define a getter/setter using the same syntax as a
property means defining simple getter/setter methods is pointless.

- having simple getter/setters is loss-less as it's inlined anyways; it's just
messy source.

- at least many of us agree that interfaces and refactoring trump inheritance.

- it would be cool if structs could be made to conform to interfaces.

- it would be cool if getting the sizeof and alignof a class was easier.

- encapsulation is useful only because it prevents people from lazily
circumventing interfaces.  Is it possible for a module to make everything
private except the interfaces?  (enforcement by denying access to the symbols
at compile time?)

- there is no longer a benefit to having the code and data local to one another
on the modern x86 platform because code and data have separate dedicated cache
regions.
Apr 16 2007
parent reply Lars Ivar Igesund <larsivar igesund.net> writes:
Dan wrote:

 - at least many of us agree that interfaces and refactoring trump
 inheritance.
It's often a good solution, but far from always.
 
 - it would be cool if structs could be made to conform to interfaces.
I very much agree with this. See http://d.puremagic.com/issues/show_bug.cgi?id=1023 -- Lars Ivar Igesund blog at http://larsivi.net DSource, #d.tango & #D: larsivi Dancing the Tango
Apr 17 2007
parent Dan <murpsoft hotmail.com> writes:
Lars Ivar Igesund Wrote:
 http://d.puremagic.com/issues/show_bug.cgi?id=1023
Ooo.. nifty. A link! If indeed we enumerated the properties in the same way that we enumerated variadic arguments in a function, then we could very reasonably write our own interface checking for structs, and someone could release a template that performed checking quite readily; with debug{} else{} thrown into the template, it could do very well indeed! Sincerely, Dan
Apr 17 2007