digitalmars.D - composition vs inheritance
- spir (58/58) Mar 16 2011 composition vs inheritance
- Steven Schveighoffer (6/27) Mar 16 2011 From the article: "Of course, these are not arguments against inheritan...
- Andrei Alexandrescu (12/22) Mar 16 2011 That's not such a common encounter. There are many conditions that the
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
Mar 16 2011
On Wed, 16 Mar 2011 08:01:46 -0400, spir <denis.spir gmail.com> wrote: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) {...}From the article: "Of course, these are not arguments against inheritance per se. Inheritance affords a great deal of power, including substitutability and/or the ability to override virtual functions." i.e., use inheritance because your design requires it. -Steve
Mar 16 2011
On 03/16/2011 07:01 AM, spir wrote: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.You are exaggerating the frequency of certain situations and needs.For instance, say I have 3 kinds of Xs X1 X2 X3.That's not such a common encounter. There are many conditions that the three kinds must satisfy - such as they must have a lot in common and very few differences. Also, all differences must have been thought over at X's creation time and put in the interface of X. THEN you are supposed to use an inheritance hierarchy. This is less frequent than people initially thought. In the 1980s it was believed that everything would belong in a hierarchy and the only challenge was to find them "good" hierarchies. Now it is quite clear things aren't all that simple. Andrei
Mar 16 2011