Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / February 2008

Tip: Looking for answers? Try searching our database.

Interface inheritance vs Implementation inheritance.

Thread view: 
Daniel Pitts - 19 Feb 2008 18:08 GMT
(x-posted to c.object and c.l.java.programmer)
First, a quick bit about my background; most of my OO experience comes
from Java, with some C++ in my past. Recently in comp.object, there was
a thread "Inheritance of implementation: what is reason of".  While the
subject line could use some grammatic tweaking, the point was eventually
made clear.

I was thinking about it, and it seems to me that implementation
inheritance is a convenience that leads to bad design and mistakes.  By
convenience, I mean that often a programmer will design the an interface
and the implementation together in one source unit (e.g. a class).
Alternatively, you can define a separate interface (lets call it IFoo)
in one source unit, and an implementation (FooImpl).  FooImpl is *also*
an interface in many languages, it just happens to have the associated
implementation.

So far, not that big of a deal.  The convolution comes when you add in
access modifiers.  For instance, in Java you can mark methods/fields as
private, protected, package-private, or public.  Now, you have up to 4
interfaces to the implementation.  Only certain code units can see some
of the interfaces, but managing that contract becomes troublesome,
especially for the "protected" interface, as many programmers don't
design their classes for inheritance but the class gets used that way.

To me, polymorphic behavior is important, and "implementation sharing"
is a very useful convenience. I think that they are often co-mingled
concepts that should be separated.  I have a few ideas on how I might do
this, at the language level, but I wanted to see if my above thoughts on
the subject stirred any interesting discussions.

My main point is that classes should use composition to gain behavior,
possibly with an easy mechanism for delegation. The *only* thing that
should be automatically inherited should be the interface.  This
eliminates the need for (and usefulness of) the "protected" access modifier.

Signature

Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

andrew queisser - 19 Feb 2008 19:03 GMT
> (x-posted to c.object and c.l.java.programmer)
>
[quoted text clipped - 3 lines]
> eliminates the need for (and usefulness of) the "protected" access
> modifier.

In C++ there are various ways implementation inheritance is useful in ways
other than inheritance of default implementation, e.g. STL, ATL, WTL, all of
which use some form of implementation inheritance to achieve efficiency.

I think the primary problem people are concerned about is implementation of
inheritance for virtual functions. Perhaps this distinction is not
meaningful outside of the C++ world.

Andrew
Peter Duniho - 19 Feb 2008 19:10 GMT
> [...]
> My main point is that classes should use composition to gain behavior,
> possibly with an easy mechanism for delegation. The *only* thing that
> should be automatically inherited should be the interface.  This
> eliminates the need for (and usefulness of) the "protected" access  
> modifier.

I have a sense that in spite of asking the question, you may have already  
decided on the answer.  I don't intend to get sucked too deep into this  
conversation.  Especially given the somewhat dubious cross-posting.

That said, I disagree.  I do agree that inheriting an implementation and  
implementing an interface are not the same thing, but I disagree that only  
the latter is a viable approach.  Both are important and useful approaches  
in OOP.  Interfaces are good for when there's a specific abstract contract  
that any object ought to be able to fulfill.  Inheriting implementation is  
good for when an object really "is" a more-specific version of some  
existing object.  And of course composition is also useful, when your  
object isn't really a more-specific version of some existing object but  
you still need to take advantage of an existing implementation of an  
object.

In Java, why should a new class that inherits Container have to  
reimplement all of the Container class's containment interface?  If all  
you want to do is provide a Container with some specific visual behavior,  
why should you also have to reimplement all of the non-visual containment  
behavior when there's a working, useful class that already does all that?

Likewise, abstract classes often (in fact, usually IME, otherwise they'd  
be interfaces) provide _some_ functionality that only needs one or a few  
actual abstract members to be implemented in order to get the full  
functionality of the abstract class.  For example, InputStream in Java  
where you only have to implement "int read()" in a derived class in order  
for the other two InputStream methods that read data to work.  There are  
often performance advantages to overriding those other two methods as  
well, but if that's not a design goal why should the implementor of the  
derived class be forced to reimplement them anyway (especially given that  
they are very likely to just reimplement them exactly as the abstract  
class has implemented them, except possibly by reintroducing all the bugs  
that the original implementor already found and fixed in their  
implementation).

Is inheritance overused?  I'd agree that it is.  Programmers often inherit  
when they should either composite or implement an interface instead.  But  
I disagree that that somehow means that inheriting an implementation is a  
priori bad.  There is still plenty of good examples of useful and proper  
inheritance of an implementation.

Pete
Daniel Pitts - 19 Feb 2008 21:27 GMT
>> [...]
>> My main point is that classes should use composition to gain behavior,
[quoted text clipped - 7 lines]
> into this conversation.  Especially given the somewhat dubious
> cross-posting.
I only cross-posted to cljp because I'm regular there, and appreciate
their input.

> That said, I disagree.  I do agree that inheriting an implementation and
> implementing an interface are not the same thing, but I disagree that
[quoted text clipped - 13 lines]
> containment behavior when there's a working, useful class that already
> does all that?
That is a perfectly valid point.  My thoughts are that it should be
*easy* to "borrow" implementation from another object, without using
inheritance but instead using composition.  To borrow your Container
example: Say you have MyContainer which implements the Container
interface, and delegates (with as clean a syntax as possible) most of
its behavior to another Container instance.  You don't have to
re-implement the containment behavior.

> Likewise, abstract classes often (in fact, usually IME, otherwise they'd
> be interfaces) provide _some_ functionality that only needs one or a few
[quoted text clipped - 9 lines]
> reintroducing all the bugs that the original implementor already found
> and fixed in their implementation).
I think what you just described is related to (but not exactly) the
Template design pattern. I think that the problem solved by the Template
pattern can be solved using a callback pattern instead.

> Is inheritance overused?  I'd agree that it is.  Programmers often
> inherit when they should either composite or implement an interface
> instead.  But I disagree that that somehow means that inheriting an
> implementation is a priori bad.  There is still plenty of good examples
> of useful and proper inheritance of an implementation.
I'm not saying that it is always and automatically bad. I guess my main
point was that there are situations where, due to many language
limitations, it is necessary to avoid a massive amounts of boiler-plate
delegation code.  If you had a convenient way (say one or two source
lines) to "borrow" all/most implementation from another class, would you
still feel that implementation inheritance is still necessary?

Signature

Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

Peter Duniho - 19 Feb 2008 21:43 GMT
> [...]
> I'm not saying that it is always and automatically bad. I guess my main  
[quoted text clipped - 3 lines]
> lines) to "borrow" all/most implementation from another class, would you  
> still feel that implementation inheritance is still necessary?

I guess I can only at this point answer "it depends".  It seems to me that  
the current, widely-used implementation inheritance syntax is pretty much  
just that: a convenient way to borrow implementation from another class.

I would have to see what this alternative syntax would look like to answer  
more definitively, but it's not clear to me that it'd be any different in  
practice from simply inheriting an implementation directly (assuming that,  
as with interfaces, a "borrowing" class still tests "true" for whether it  
"is" one of these "borrowed" things...if that's not the case, then I'd say  
that's a glaring omission of the proposal).

Or, looking at the question from another angle, if it's okay to "borrow"  
implementation from another class, what does it matter whether it was  
borrowed in the form of inheritance or in the form of a new type of  
composition that looks just like inheritance?

I'm reading this in the Java newsgroup, and perhaps the "comp.object"  
crowd has a more thorough academic understanding of OOP practices and  
principles than I do.  But I admit, based on what you've written so far  
I'm not really clear on the distinction between the way things are now and  
what you're suggesting they could be, at least from a practical standpoint.

Pete
Patricia Shanahan - 19 Feb 2008 22:05 GMT
...
> Or, looking at the question from another angle, if it's okay to "borrow"
> implementation from another class, what does it matter whether it was
> borrowed in the form of inheritance or in the form of a new type of
> composition that looks just like inheritance?
...

I think the big question is what gets exposed to users of the borrowing
class.

To make this a bit more specific, consider ArrayList. It implements a
series of interfaces. Those describe the general behavior its callers
can depend on: it's a list, it has fast random access, it can be cloned
and serialized, and it has an Iterator.

In addition, it extends AbstractList. That seems to me to be part of its
implementation, and not something I would use in my code. And yet, a
class outside java.util could declare:

AbstractList<String> someList = new ArrayList<String>();

It might be advantageous to split AbstractList, for example to provide
different implementations depending on whether the list has fast random
access. That cannot be done, because of the public nature of the uses of
AbstractList.

Patricia
Lasse Reichstein Nielsen - 20 Feb 2008 06:15 GMT
> To make this a bit more specific, consider ArrayList. It implements a
> series of interfaces. Those describe the general behavior its callers
[quoted text clipped - 11 lines]
> access. That cannot be done, because of the public nature of the uses of
> AbstractList.

Agreed.
I wouldn't mind a language where implementation inheritance wasn't public,
i.e., your type only consists of interfaces. If you extend another class,
you also implements its interfaces, but the extended class is not part
of your type.

And I would also like an easy way to create a composition, e.g.,

class Foo implements Bar(b) {
   private Bar barbarbar implements Bar; // or delegates Bar
   public Foo(int i) {
     super(i);
     this.barbarbar = new Bar(i);
   }
   //...
}

/L
Signature

Lasse Reichstein Nielsen  -  lrn@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
 'Faith without judgement merely degrades the spirit divine.'

Robert Martin - 20 Feb 2008 13:03 GMT
> I wouldn't mind a language where implementation inheritance wasn't public,
> i.e., your type only consists of interfaces. If you extend another class,
> you also implements its interfaces, but the extended class is not part
> of your type.

You mean like in C++?

class MyContainer : private SomeContainer {
...
}

> And I would also like an easy way to create a composition, e.g.,
>
[quoted text clipped - 6 lines]
>     //...
>  }

If you think about that a bit longer, you'll realize that an easy way
to create composition IS inheritance.  Or rather, inheritance is an
easy way to create composition.

Every method of the component gets redeclared in the composer.  When
those methods are called on the composer, the component's
implementation is invoked.

Now change the words composer to base, and component to derivative and
you'll see the sentence is true.

Perhaps what you are after is a way to make sure that the composer
cannot be cast (explicitly or implicitly) to the component.  That's
what private inheritance gives you.

I conclude from this that we'd all be happy if Java had multiple
inheritance and private inheritance.

;-)

Signature

Robert C. Martin (Uncle Bob)  | email: unclebob@objectmentor.com
Object Mentor Inc.            | blog:  www.butunclebob.com
The Agile Transition Experts  | web:   www.objectmentor.com
800-338-6716                  |

Silvio Bierman - 20 Feb 2008 14:13 GMT
> If you think about that a bit longer, you'll realize that an easy way to
> create composition IS inheritance.  Or rather, inheritance is an easy
[quoted text clipped - 15 lines]
>
> ;-)

I disagree. Inheritance and interfaces a la Java have one important
distinction: interfaces introduce no implicit implementation of methods.
Since Java does not support multiple inheritance implementation
inheritance is too limited for many use cases. C++ supports MI but in a
very disturbed way (although I was quite happy with it when it was
introduced into the language I have learned to really hate it). The
issues of virtual bases and multiple down-cast paths leading to
different implementations of the same function signature are painful. It
is unclear how any implementation of multiple implementation inheritance
could circumvent these issues.

The advantage of the Java interface concept is that a class implementing
an interface (and not extending any other class than Object) will have
to explicitly define how the interface methods are implemented. If it
extends multiple interfaces with shared function signatures the seaming
ambiguity is resolved at the class level itself.

Unfortunately Java lacks a simple way of expressing interface
delegation. I would have loved something like:

interface I1
{
  public void f1();
  public void f2();
  public void f3();
}

class C1 implements I1
{
  public void f1() { /*...*/ }
  public void f2() { /*...*/ }
  public void f3() { /*...*/ }
}

class C2 implements I1, I2
{
  private C1 c1a;
  private C1 c1b;
  public I1() { return c1a != null ? c1a : c1b; } /* NOT SUPPORTED */
  public void f2() { /* THIS IS AN OVERRULE IMPLEMENTATION */ }
}

where the constructor-like syntax of the 'public I1() { /*...*/}'
notation implies that all methods declared in I1 and not declared in C2
or I2 are implicitly implemented such that given a C2 reference c2
calling c2.f1() is equal to c2.I1().f2().

This syntax would be ideal for implementing partial delegations of
interfaces with many methods when writing wrapper classes (the JDBC or
Servlet interfaces anyone?).

Would such syntax/semantics exist I would be happy to drop
implementation inheritance in most places.

Kind regards,

Silvio Bierman
Robert Martin - 20 Feb 2008 12:56 GMT
> I think the big question is what gets exposed to users of the borrowing
> class.
[quoted text clipped - 14 lines]
> access. That cannot be done, because of the public nature of the uses of
> AbstractList.

This is the reason that C++ has private inheritance.  A privately
inherited base class is inaccessible to any users or further subclasses.

Signature

Robert C. Martin (Uncle Bob)  | email: unclebob@objectmentor.com
Object Mentor Inc.            | blog:  www.butunclebob.com
The Agile Transition Experts  | web:   www.objectmentor.com
800-338-6716                  |

Daniel Pitts - 19 Feb 2008 22:10 GMT
>> [...]
>> I'm not saying that it is always and automatically bad. I guess my
[quoted text clipped - 9 lines]
> pretty much just that: a convenient way to borrow implementation from
> another class.
Currently, inheritance of classes "borrows" both the implementation
*and* interface. The thing is that interface and implementation are
borrowed together, and you have to take extra steps if you only want the
implementation or only the interface.  I think it might be good to
separate those concepts.

> I would have to see what this alternative syntax would look like to
> answer more definitively, but it's not clear to me that it'd be any
> different in practice from simply inheriting an implementation directly
> (assuming that, as with interfaces, a "borrowing" class still tests
> "true" for whether it "is" one of these "borrowed" things...if that's
> not the case, then I'd say that's a glaring omission of the proposal).
If the interface "lives" separately from the implementation, then the
borrow can choose to also borrow the interface (or some parent
interface, or some composite interface).

> Or, looking at the question from another angle, if it's okay to "borrow"
> implementation from another class, what does it matter whether it was
> borrowed in the form of inheritance or in the form of a new type of
> composition that looks just like inheritance?
Because the borrowing can be more pick-and-choose in the new way,
instead of the all-or-nothing of inheritance. Also, there are times when
your interface maps one-to-one to another class for a few methods. It
could be easier to pick out those methods.

> I'm reading this in the Java newsgroup, and perhaps the "comp.object"
> crowd has a more thorough academic understanding of OOP practices and
> principles than I do.  But I admit, based on what you've written so far
> I'm not really clear on the distinction between the way things are now
> and what you're suggesting they could be, at least from a practical
> standpoint.
I guess the main difference is the syntax, but I believe it adds
flexibility too.

Signature

Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

Daniele Futtorovic - 19 Feb 2008 23:58 GMT
>>> [...] I'm not saying that it is always and automatically bad. I
>>> guess my main point was that there are situations where, due to
[quoted text clipped - 42 lines]
> I guess the main difference is the syntax, but I believe it adds
> flexibility too.

/* The following deliberately sets itself strictly within the context of
the Java Programming Language, as it often most beneficial to have a
practical reference to focus the discussion. */

It seems to me all practical examples you gave in this thread are
feasible with the current grammar of Java. There are two discrete
models, one for "borrowing" an interface and one for "borrowing" an
implementation; the first one is called implementing an interface and
the second one extending a class.
The practice of always providing both for all classes isn't ubiquitous,
or even widespread. But, while I grant this may cause you much grief on
diverse occasions, it is simply not an argument against the grammar of
Java, but only potentially against some of its uses.
On the subject of "borrowing an implementation", let me point out that
getting rid of protected modifiers, which you seem to aim at, would
effectively _force_ upon you _all_ the implementation that isn't public
-- so much for "borrowing can be more pick-and-choose".

The use of composition in a given class is clearly a good idea and
obviously superior to inheritance simply in that you can only inherit
once, but can compose many times. There are various stances one can take
towards composing, from aggressive encapsulating of any functionality
that lurks its head to lazily refactoring en masse. Note, however, that
composition does not replace, or indeed affect, inheritance essentially:
it merely replaces it in the context of one given class. Talking of
composition merely _shifts_ the question of inheritance towards the
classes actually implementing the encapsulated functionality. Now you
may argue that, since through composition you grant the API user means
to replace functionality in transparent manner, you can keep all your
implementations of the encapsulated functionality locked tight. This
would surely be a valid choice, and it may for any given case be
justified or not -- but one thing's for sure and that's that you would
be giving your customers less for their money by prohibiting re-use of
code (unless you make it public throughout, which I don't suppose you'd
advocate).

You've been occasionally talking about "clean syntax", "few lines of
code", suggesting your aim was at least partially at some kind of
syntactic sugar. So let me state this: Java boilerplate code is GREAT.
And in my view *any* request for modification of the JLS, the sole
argument in favour of which is that it saves typing, does not deserve
attention (nota bene: shorter syntax is not the same thing as greater
clarity).
What in my opinion is one of the greatest things about Java is that, at
the basic level, the language features very few denizens: objects,
primitives, classes, interfaces, functions, fields -- that's about it.
With these basic entities, such high-level concepts as callbacks,
closures or concurrent APIs can be built. Entirely transparently so. If
someone wishes to see how it's done, they can, by simply reading the
source code (except for native methods). They can reproduce it freely.
No behind-the-scenes voodoo. Yes, that's it in two words: no voodoo.

At least that's what it was like until they introduced the enhanced
for-loop back in Tiger (I'm not entirely sure it was the first
occurrence, but it's just an example, don't quote me on that). And I can
only hope they won't get through with the closures stuff they're
planning for 1.7. This to me is clearly a step in the wrong direction,
because it /hides/ what's going on. It's voodoo. The enhanced for-loop
takes an Iterable, initialises an iterator, and repeatedly calls next()
while checking hasNext(). We know that because it's written in the
specification. But the point is that nowhere can we see that in plain
Java code anymore.
Now don't get me wrong: the enhanced for-loop is really quite a pleasure
to use, and even I, who am reluctant to it, have found myself making
increasing use of it. But when it comes down to it and I am confronted
with the choice between a short syntax where it's unclear what's going
on and a longer syntax where you see precisely what's going on -- I'm
always going to side with the latter. When you know what you're doing
you can always assess that each bit of effort you provide, no matter how
much of it is overall necessary, is productive; while in the opposite
case you cannot tell whether it may be unproductive or, even worse,
counter-productive.

df.
Daniel Pitts - 20 Feb 2008 00:35 GMT
>>>> [...] I'm not saying that it is always and automatically bad. I
>>>> guess my main point was that there are situations where, due to
[quoted text clipped - 60 lines]
> effectively _force_ upon you _all_ the implementation that isn't public
> -- so much for "borrowing can be more pick-and-choose".
Anything that was "protected" is still a "public interface" to the
inheritors.  You can separate that out quite easily in all the
circumstances I can think of.

> The use of composition in a given class is clearly a good idea and
> obviously superior to inheritance simply in that you can only inherit
[quoted text clipped - 13 lines]
> code (unless you make it public throughout, which I don't suppose you'd
> advocate).
Since the "protected interface" is specific to an implementation, it
should be called out differently IMO.  As far as re-use goes, its
important to limit re-use to things you expect to maintain in the
future.  You can still add the hooks to have extensibility in your code,
enabling re-use. You just use a different pattern.

> You've been occasionally talking about "clean syntax", "few lines of
> code", suggesting your aim was at least partially at some kind of
[quoted text clipped - 3 lines]
> attention (nota bene: shorter syntax is not the same thing as greater
> clarity).
I agree short/clever != clear, and this is not in the context of Java,
despite the fact that I posted to cljp :-)
The syntax would be explicit and compact.  Having not thought greatly
into it. "MyFoo extends Foo {}" might become "MyFoo implements Foo { Foo
foo; delegate "*" to foo; }

Yes, its a little more typing, but you can replace that "*" with more
specific names, etc...  Thats where you get the pick-and-choose.  It
also allows inversion-of-control in the inheritance structure. Think "I
want a MyFoo that extends FooBar, and I want another MyFoo that extends
FooLish".

> What in my opinion is one of the greatest things about Java is that, at
> the basic level, the language features very few denizens: objects,
[quoted text clipped - 4 lines]
> source code (except for native methods). They can reproduce it freely.
> No behind-the-scenes voodoo. Yes, that's it in two words: no voodoo.
I agree with that.  I'm not suggesting modifying Java, it would have to
be another (possibly not-yet-existent) language.

> At least that's what it was like until they introduced the enhanced
> for-loop back in Tiger (I'm not entirely sure it was the first
[quoted text clipped - 16 lines]
> case you cannot tell whether it may be unproductive or, even worse,
> counter-productive.
True, and hopefully the "example" syntax I use above helps to show that
I'm actually exposing more information rather than less.  The "delegate"
keyword would expose exactly which methods (by name or whatever) are
being exposed.

> df.

Thanks (everyone) for the feedback so far. Even if it appear(s/ed) that
I already made up my mind, it is something that I'm working out for
myself, but want feedback to help confirm or deny my suspicions.

Signature

Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>

Patricia Shanahan - 20 Feb 2008 01:47 GMT
...
> With these basic entities, such high-level concepts as callbacks,
> closures or concurrent APIs can be built. Entirely transparently so. If
> someone wishes to see how it's done, they can, by simply reading the
> source code (except for native methods). They can reproduce it freely.
> No behind-the-scenes voodoo. Yes, that's it in two words: no voodoo.

I've heard the "no voodoo" argument many times before, initially from
people telling me why assembly languages were better than Fortran or
Algol. Later, procedural languages were better than OO, because you can
see exactly what function will be invoked, no virtual call voodoo.

The increasing semantic gap between what the programmer writes and
what the processor does has been a major theme of programming language
development. The effect has been to greatly increase the effectiveness
of programmers by automating a lot of details.

What's different this time? Does Java really have *exactly* the right
amount of voodoo, so that adding any more will take it past the current
sweet spot?

> At least that's what it was like until they introduced the enhanced
> for-loop back in Tiger (I'm not entirely sure it was the first
> occurrence, but it's just an example, don't quote me on that).

I like the enhanced for-loop. If I just want to do something to every
element in a collection an enhanced for-loop expresses my intent more
directly and clearly than an Iterator idiom.

Patricia
Daniele Futtorovic - 20 Feb 2008 18:13 GMT
> Daniele Futtorovic wrote: ....
>> With these basic entities, such high-level concepts as callbacks,
[quoted text clipped - 18 lines]
>  amount of voodoo, so that adding any more will take it past the
> current sweet spot?

You're right, so maybe the emphasis shouldn't be on /how much/ voodoo,
but on /how/ voodoo. The point would be to find a minimal set of
building blocks, of basic entities, which encapsulate the voodoo, and to
keep the set minimal. Especially not to inflate it with synonyms which
make no semantical addition.

>> At least that's what it was like until they introduced the enhanced
>>  for-loop back in Tiger (I'm not entirely sure it was the first
[quoted text clipped - 3 lines]
>  element in a collection an enhanced for-loop expresses my intent
> more directly and clearly than an Iterator idiom.

Not functionally so, for functionally, you are using an Iterator. What's
happened is that, from the point of view of the code, you've introduced
a new entity which, though linguistically distinct, makes no semantic
addition. It's a synonym.

 df.
Patricia Shanahan - 20 Feb 2008 18:33 GMT
...
>> What's different this time? Does Java really have *exactly* the right
>>  amount of voodoo, so that adding any more will take it past the
[quoted text clipped - 5 lines]
> keep the set minimal. Especially not to inflate it with synonyms which
> make no semantical addition.

All you really need is a Turing machine. Its basic entities are a state
machine, a current state, and a tape with a single read/write head. Or,
to be a bit more practical, consider the original MIPS instruction set.
Its assembly language is very simple, with few basic entities.

However, I find it far easier to express my programs in Java than in any
assembly language.

>> I like the enhanced for-loop. If I just want to do something to every
>>  element in a collection an enhanced for-loop expresses my intent
[quoted text clipped - 4 lines]
> a new entity which, though linguistically distinct, makes no semantic
> addition. It's a synonym.

Sure. Even assembly languages add new entities which, though
linguistically distinct, make no semantic addition. For example, "nop"
is often provided as a mnemonic, but mapped to some existing operation
that does nothing. What's wrong with that, as long as it makes the
resulting programs a clearer expression of the programmer's intent?

Patricia
Robert Martin - 20 Feb 2008 12:51 GMT
>  My thoughts are that it should be *easy* to "borrow" implementation
> from another object, without using inheritance but instead using
[quoted text clipped - 3 lines]
> Container instance.  You don't have to re-implement the containment
> behavior.

True, but you DO have to write all the delegating functions.  Ick.  Why
should I have to write a bunch of brain-dead delegation functions every
time I want to reuse some nice piece of implementation.

It would be trivial to add language feature that did
composition-and-delegation for you.  It might look like this:

class MyContainer composes SomeContainer {
 ...
}

This would create a hidden instance variable for SomeContainer, and
automatically write delegation functions in MyContainer.

Indeed, you might be able to compose more than one class.  Let's say
you wanted to have a contaier that was observable:

class MyContainer composes SomeContainer, Subject {
 ...
}

How cool would this be!  Automatic reuse through composition!!!

There is a name for this feature.

It's called Multiple Inheritance.

Signature

Robert C. Martin (Uncle Bob)  | email: unclebob@objectmentor.com
Object Mentor Inc.            | blog:  www.butunclebob.com
The Agile Transition Experts  | web:   www.objectmentor.com
800-338-6716                  |

Mike Schilling - 21 Feb 2008 00:50 GMT
> True, but you DO have to write all the delegating functions.  Ick.
> Why should I have to write a bunch of brain-dead delegation
[quoted text clipped - 10 lines]
> This would create a hidden instance variable for SomeContainer, and
> automatically write delegation functions in MyContainer.

It would also be trivial for an IDE to generate the delegation methods
for you, and no languages changes are required for that.
S Perryman - 21 Feb 2008 12:06 GMT
>>True, but you DO have to write all the delegating functions.  Ick.
>>Why should I have to write a bunch of brain-dead delegation
>>functions
>>every time I want to reuse some nice piece of implementation.

>>It would be trivial to add language feature that did
>>composition-and-delegation for you.  It might look like this:

>>class MyContainer composes SomeContainer {
>> ...
>>}

>>This would create a hidden instance variable for SomeContainer, and
>>automatically write delegation functions in MyContainer.

> It would also be trivial for an IDE to generate the delegation methods
> for you, and no languages changes are required for that.

The big problem with delegation is correctness (safety specifically) :

type T
{
   Delegate D ;

   op() ;
}

T::op() = D.op() ;

Delegating service execution to some other object(s) D, would require
that D cannot be messed with (re-assigned, deleted etc) .

With heap-based object allocation, such guarantees become difficult.
With prog langs that can 'embed' a D into the representation of T (C++ ,
the "expanded" concept in Eiffel etc) , delegation is safer.

Regards,
Steven Perryman
Silvio Bierman - 21 Feb 2008 12:11 GMT
>> True, but you DO have to write all the delegating functions.  Ick.
>> Why should I have to write a bunch of brain-dead delegation
[quoted text clipped - 13 lines]
> It would also be trivial for an IDE to generate the delegation methods
> for you, and no languages changes are required for that.

IDEs should only generate code to save you some typing, like wrapping
code in a try/catch block.
Forwarding interface methods to an implementing object is not about
typing. It becomes nasty when you have no control over the interfaces
(JDBC/Servlet API wrappers are a good example as I mentioned somewhere
in this thread) and their development over time. If I want to write a
wrapper around such an interface I may just have to implement two or
three methods and simply forward the rest.

Having the IDE generate my "forward the rest" code will result in a
class that only works with a specific version of the interface. If you
own the interface this is already a maintenance nightmare requiring very
advanced refactoring support to be manageable but if it is a public
interface that evolves (usually this means new methods are added in
time) your code gets broken in time automatically.

IDEs generating code have very often been an excuse to create horrendous
constructs. Just look at the EJB specs for examples. Microsoft's MFC was
a prime candidate as well.

Regards,

Silvio Bierman
Mike Schilling - 21 Feb 2008 15:14 GMT
>>> True, but you DO have to write all the delegating functions.  Ick.
>>> Why should I have to write a bunch of brain-dead delegation
[quoted text clipped - 31 lines]
> methods are added in time) your code gets broken in time
> automatically.

That's true of any interface that adds methods.  Classes that formerly
implemented it successfully will fail to compile.
Lew - 21 Feb 2008 15:28 GMT
> "Silvio Bierman" <sbierman@jambo-software.com> wrote in message
>> Having the IDE generate my "forward the rest" code will result in a
[quoted text clipped - 7 lines]
> That's true of any interface that adds methods.  Classes that formerly
> implemented it successfully will fail to compile.

Ditto with abstract classes and new abstract methods.

Signature

Lew

Mike Schilling - 21 Feb 2008 16:26 GMT
>> "Silvio Bierman" <sbierman@jambo-software.com> wrote in message
>>> Having the IDE generate my "forward the rest" code will result in
[quoted text clipped - 7 lines]
>> That's true of any interface that adds methods.  Classes that
>> formerly implemented it successfully will fail to compile.

And given how the JVM and bytecode work, it would, unless I'm missing
something, be equally true of a Java language feature that performed
delegation.  That is, the feature would generate bytecode to do the
forwarding (possibly being clever enough not to generate forwarding
methods for methods that are hand-coded), not adjust its beahcior at
run-time according to the version of the interface currently loaded.

> Ditto with abstract classes and new abstract methods.

Yup.  One of the advantages of defining an abstract class that clients
can extend vs.defining an interface for them to implement, is that you
can later add new methods by giving them default implementations.
Obviously this won't always work, and there are disadvantages to
abstract classes as well, but it's something to consider when
designing a framework.
Silvio Bierman - 26 Feb 2008 22:40 GMT
> And given how the JVM and bytecode work, it would, unless I'm missing
> something, be equally true of a Java language feature that performed
[quoted text clipped - 11 lines]
> abstract classes as well, but it's something to consider when
> designing a framework.

I am aware that a compiler trick is not enough to implement such a
feature. It would require auto-delegation logic at the JVM level which
makes it unlikely to ever happen. Looking at the hoops they jumped
through to sort-of implement generics without proper JVM support does
not give me much hope.

Regards,

Silvio
Mike Schilling - 27 Feb 2008 01:37 GMT
>> And given how the JVM and bytecode work, it would, unless I'm
>> missing
[quoted text clipped - 23 lines]
> does
> not give me much hope.

You misunderstand.  What you see are the hoops they jumped through to
add generics without introducing either source or binary
incompatibility when a non-generic class is converted to a generic
one.  You can argue about how important this goal was, but I've never
seen a superior solution to it.

> Regards,
>
> Silvio
Roger Lindsjö - 21 Feb 2008 18:42 GMT
> Having the IDE generate my "forward the rest" code will result in a
> class that only works with a specific version of the interface. If you
[quoted text clipped - 6 lines]
> constructs. Just look at the EJB specs for examples. Microsoft's MFC was
> a prime candidate as well.

In that case you could use a build a Proxy which just intercepts the
methods you recognize.

However, trying to be "forward compatible" could still be a mess as not
only might the interface have new methods added to it, but the existing
methods could change their meaning which would probably make the
wrapping code invalid anyway.

Signature

Roger Lindsjö

Robert Martin - 20 Feb 2008 12:44 GMT
> My main point is that classes should use composition to gain behavior,
> possibly with an easy mechanism for delegation. The *only* thing that
> should be automatically inherited should be the interface.  This
> eliminates the need for (and usefulness of) the "protected" access modifier.

Polymorphism is a good thing, and the use of interfaces to achieve
polymorphism should be encouraged in Java.  On the other hand, there
are times when inheritance of implementation is -- pleasant.

The standard Observer is a common enough example.  Observable classes
need to be able to register and notify observers.  We can create a
non-polymorphic class that provides this behavior:

public class Subject {
 private List<Observer> observers = ArrayList<Observer>();
 public void register(Observer o) {observers.add(o);}
 public void notify() {
   for (Observer o : observers)
     o.update();
 }
}

Now any observable can inherit this class and enjoy the implementation
of register and notify.  Note that there is no polymorphism involved,
or intended.  We simply want the implementation.

Of course the creators of Java were too wimpy to add true multiple
inheritance.  So by inheriting Subject, we use up the one and only
inheritance slot for our observable class.  That's a shame.  If Java
had true multiple inheritance then we'd be able to mix-in simple
implementations like this, with  other classes.

As things stand, it is probably best to use composition to bring
Subject into the observable, and use delegation to call the register
and notify functions. But not because polymorphic interfaces are always
better; rather because Java was crippled by the decision to turn
multiple inheritance into the bogey man.
Signature

Robert C. Martin (Uncle Bob)  | email: unclebob@objectmentor.com
Object Mentor Inc.            | blog:  www.butunclebob.com
The Agile Transition Experts  | web:   www.objectmentor.com
800-338-6716                  |

H. S. Lahman - 20 Feb 2008 18:31 GMT
Responding to Pitts...

> I was thinking about it, and it seems to me that implementation
> inheritance is a convenience that leads to bad design and mistakes.  By
[quoted text clipped - 4 lines]
> an interface in many languages, it just happens to have the associated
> implementation.

I think it is important to distinguish between simple implementation
inheritance and overrides of implementation inheritance. Overrides have
proven to be a Really Bad Idea if one cares about maintainability.

However, simple implementation inheritance is almost always benign. To
create a situation where maintenance of the generalization can break
existing clients requires a large and complicated generalization, which
should make one look for delegation solutions in the first place. Also,
the foot-shooting examples I've seen with simple implementation
inheritance can be attacked on other design grounds.

The problem is that every OOPL I know that supports implementation
inheritance also supports overrides because the underlying jump table
mechanism is the same. But just because a language supports a feature
doesn't mean one needs to use it. I think an OOA/D methodological
prohibition of using overrides is sufficient.

> So far, not that big of a deal.  The convolution comes when you add in
> access modifiers.  For instance, in Java you can mark methods/fields as
[quoted text clipped - 3 lines]
> especially for the "protected" interface, as many programmers don't
> design their classes for inheritance but the class gets used that way.

IMO, the public/private stuff found in OOPLs is just syntactic sugar
that saves the developer some keystrokes at the cost of potentially
introducing foot-shooting. There is nothing these qualifiers provide
that one could not do with different developer-defined interfaces and
associating specific clients with specific interfaces. [In the
translation MDA profile I use for OOA, those qualifiers are not
available. A full code generator has no problem generating correct code
without them.]

[FWIW, I think Protected is a kludge and the only place I would use it
is to support a unit test harness -- for which it is very convenient.
But let's not go there...]

> To me, polymorphic behavior is important, and "implementation sharing"
> is a very useful convenience. I think that they are often co-mingled
> concepts that should be separated.  I have a few ideas on how I might do
> this, at the language level, but I wanted to see if my above thoughts on
> the subject stirred any interesting discussions.

I agree they are different things. But I think one can prevent them from
becoming co-mingled in a detrimental way methodologically. The OOPLs
/implement/ OOA/D; methodologies drive OOA/D.

[Note that the OOPLs do much more egregious things, such as combining
message and method, simply because they are 3GLs. But those things are
rendered harmless by getting the OOA/D right.]

> My main point is that classes should use composition to gain behavior,
> possibly with an easy mechanism for delegation. The *only* thing that
> should be automatically inherited should be the interface.  This
> eliminates the need for (and usefulness of) the "protected" access
> modifier.

Unrestrained composition has its own set of problems as it can trash
object cohesion.

Signature

There is nothing wrong with me that could
not be cured by a capful of Drano.

H. S. Lahman
hsl@pathfindermda.com
Pathfinder Solutions
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development".  Email
info@pathfindermda.com for your copy.
Pathfinder is hiring:
http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH



Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.