composition vs inheritance
I have carefully read the document "Prefer composition to inheritance", from
C++ coding standards, at
http://www.artima.com/cppsource/codestandards3.html, by Herb Sutter and Andrei
Alexandrescu.
In general, I do agree in that composition makes for a simpler scheme, and more
flexible. But when writing D code, I constantly step on the same issue that
without inheritance and (runtime type) polymorphism, I simply cannot express
/very/ common things.
For instance, say I have 3 kinds of Xs X1 X2 X3. I would like to write:
void moveTogether (X[] xs, Vector vector) {
foreach (x ; xs) {
lookAround(x);
x.move(vector);
if (isX3(x)) {
writeln(x.motto);
x.jump();
}
}
}
void lookAround (X x) {...}
Let us forget the if clause for now. There are several issue. First, I cannot
put elements of the 3 types into an X[] collection. Second, a function that
expects an X like lookAround will not accept elements of types X1 X2 X3.
Third, moveTogether will call move on X (if any) instead of the proper move on
each element's type.
How do you solve this without inheritance and polymorphism? How do you solve
this with D structs?
There is also an issue with inheritance and method dispatch (reason why I wrote
"(if any)" above): for x.move() to work, move must be defined on X even if it
does not make any sense.
This is were the if clause enters the game: some subtype(s) may have additional
data or function members that really should not be defined on the super type.
(Think at different kinds of nodes in a tree, eg a parse tree). To be able to
access them in a 'generic' func like moveTogether, I need to define fake
members on X.
This is really ugly, misleading, and costly. Then, I could as well define a
single, haevy, kind of X with all the stuff for every subtype. But doing so I
would lose the ability to specialise given members like move...
Go solves this, I guess, with its very nice notion of interface. In this case,
there may be a Mobile interface with a single method move. X1 X2 X3
automatically satisfy it by having move defined (there is no need for explicite
"implements" or inheritance). Thus, function signatures become:
void moveTogether (Mobile[] ms, Vector vector)
void lookAround (Mobile m)
...and everbody's happy (I guess).
Note: Such interfaces would also nicely replace all the ugly stuff with is()
for template preconditions:
void f (Mobile M) (M m) {...}
instead of:
void f (M) (M m) if (is(somethingIDontWantToWrite)) {...}
Actually (unsure), I think with interfaces we don't even need a generic func /
template here.
Denis
--
_________________
vita es estrany
spir.wikidot.com