Re: Composition vs. Inheritance (Was: colored point redux) (fwd)
Daniel Yoo <[email protected]> Mon, 26 Feb 2007 12:10:29 -0500 (EST)
| Newsgroups | gmane.comp.lang.lightweight |
|---|---|
| Message-ID | <[email protected]> |
My apologies, but my message didn't get through the first time; let me try again. ---------- Forwarded message ---------- Date: Mon, 26 Feb 2007 10:35:44 -0500 (EST) From: Daniel Yoo <[email protected]> To: Robbert Haarman <[email protected]> Cc: [email protected] Subject: Re: [ll-discuss] Composition vs. Inheritance (Was: colored point redux) > Or, another example, strings and linked lists are both sequences, and thus > could inherit some behavior (methods) that are common to all sequences. How > would this be accomplished by composition? Hi Robbert, Let's assume that we have some described behavior and we want to reuse that behavior without retyping it. Let's do a concrete example: let's say we do have things that support something "getitem"ish, and we'd like to provide different ways to iterate over them. We can provide some template class for iteration. I'll use Java for these examples just to be very concrete. /**********************************************************/ import java.util.Iterator; public abstract class ForwardIteration { // Returns the ith item abstract Object getItem(int i); // Returns the length abstract int len(); public Iterator iter() { class MyIter implements Iterator { int k = 0; public Object next() { return getItem(k++); } public boolean hasNext() { return k < len(); } public void remove() { throw new UnsupportedOperationException(); } } return new MyIter(); } } /**********************************************************/ For the sake of the example, here's a quick-and-dirty silly thing to fill out the template. /**********************************************************/ import java.util.Iterator; public class MyList extends ForwardIteration { private String[] items = {"hello", "world"}; public Object getItem(int i) { return items[i]; } public int len() { return 2; } static public void main(String[] args) { for (Iterator iter = new MyList().iter(); iter.hasNext() ; ) { System.out.println(iter.next()); } } } /**********************************************************/ Ok, that works. One problem, though, is allowing these things to support _multiple_ ways of iteration. How do we use inheritance to support both forward iteration and backward iteration? I'd like to be able to write BackwardIteration: /**********************************************************/ import java.util.Iterator; public abstract class BackwardIteration { // Returns the ith item abstract Object getItem(int i); // Returns the length abstract int len(); public Iterator iter() { class MyIter implements Iterator { int k = len() - 1; public Object next() { return getItem(k--); } public boolean hasNext() { return k >= 0; } public void remove() { throw new UnsupportedOperationException(); } } return new MyIter(); } } /**********************************************************/ But now MyList can't inherit from both ForwardIteration and BackwardIteration, if we live from a single-inheritance restriction. And even if we could, we've still got the Highlander problem: in the end, there can be only one. They conflict with the same method name iter(). So that's why vanilla inheritence fails as a mechanism for reuse here. In contrast, we can do what we want with object composition: /************************************************************/ import java.util.Iterator; interface Sequence { Object getItem(int i); int len(); } class ForwardIteration2 { public Iterator iter(final Sequence seq) { class MyIter implements Iterator { int k = 0; public Object next() { return seq.getItem(k++); } public boolean hasNext() { return k < seq.len(); } public void remove() { throw new UnsupportedOperationException(); } } return new MyIter(); } } /************************************************************/ Now writing an equivalent BackwardIteration2 using object composition should be no problem, and using both Iterations on a sequence is not an issue. Another difficulty with inheritance as to get reuse is that "extending" our classes requires us to edit our old source code to push those behaviors into the old code. This might not be possible under certain situations, like not having a component's source code available to us, for example. So those are some of the problems with trying to use inheritence as a mechanism for reuse in Java. The issue is that it doesn't quite compose very well, compared to object composition. I'm not sure how you plan to handle this problem in your own language, but it's something to keep in mind. PLT Scheme's doing something with "traits" to avoid this issue: http://www.cs.utah.edu/plt/publications/aplas06-fff.pdf Best of wishes!