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