D vs. placement new (for classes) aka why D needs .sizeof and

David B. Held dheld at codelogicconsulting.com
Sat Apr 14 00:39:08 PDT 2007


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



More information about the Digitalmars-d mailing list