Interface freeloading on a superclass - is it good practice?

J

jan V

It compiles and runs, although it appears to me there is something
Not at all. It just means your end object has the behaviours
described by the interface. How it got them is immaterial.

I totally disagree. It is material, see my other post for my arguments.
 
C

Chris Berg

However, IMHO, this is almost (note I don't say always) an anti-pattern.
If we used the Interface Segregation Principle, then we would not need
to have so many interfaceAdaptors.

HTH

Andrew

I hardly ever use Adapters. They are mainly there to support anonymous
inner classes, which is a quick (and dirty?) way of creating a
Listener on-the-fly. In my opinion, it sort of takes event handling
back to look somewhat like the java1.0 event model. But of course, it
all boils down to a matter of taste.
 
C

Chris Berg

So all in all, unless my prediction of trouble ahead is flawed, I think you
need to go back to the drawing board on this one.,..
I fail to see your point.
If Sun suddently changed the signature or function of, say,
java.awt.Component, I would have to re-write almost all the code I've
made the last 10 years, not just this litle snippet. Not to mention
Sun themselves - every subclass on Component would also suffer. So i
am resting quite assured that it won't happen.

Chris
 
O

Oliver Wong

Roedy Green said:
the notion of which interface does a method belong to just does not
come up in Java. A method conforming to two different interfaces
belongs to both interfaces.

You can access the method via a class reference or either interface
reference.

The issue I'm trying to raise here is what if there are three
programmers involves: Author A, Author B and myself. Author A writes an
interface "InterfaceA" which defines one method "foo()" which does one
particular thing. Author B writes an itnerface "InterfaceB" which defines
another method "foo()" which does something different.

I want to write a class that implements both these interfaces. I'd like
to write two different method bodies because the two "foo()" actions
semantically do different things, but I can't in Java, whereas I could in
C#.

This issue comes up especially when using remoting where third parties
not under your control give you files describing interfaces you must conform
to to interact with their applications.

- Oliver
 
A

Andrew McDonagh

Chris said:
I hardly ever use Adapters. They are mainly there to support anonymous
inner classes, which is a quick (and dirty?) way of creating a
Listener on-the-fly. In my opinion, it sort of takes event handling
back to look somewhat like the java1.0 event model. But of course, it
all boils down to a matter of taste.

Erm... no, they don't have anything to do with anonymous inner classes.
Yes lots of examples use anonymous inner classes derived from Adapters,
but thats completely separate.

Do you use (non static) inner classes?
 
A

Andrew McDonagh

Oliver said:
The issue I'm trying to raise here is what if there are three
programmers involves: Author A, Author B and myself. Author A writes an
interface "InterfaceA" which defines one method "foo()" which does one
particular thing. Author B writes an itnerface "InterfaceB" which defines
another method "foo()" which does something different.

But... interfaces do not specify WHAT the method does, just that there
is a public method with that signature on that TYPE of object.

Interfaces allow us to have Multiple Inheritance of

If interfaces did specify WHAT, then they would not be interfaces - they
would be Classes.
I want to write a class that implements both these interfaces. I'd like
to write two different method bodies because the two "foo()" actions
semantically do different things, but I can't in Java, whereas I could in
C#.


This problem is not just limited to Java, any language that supports
Polymorphism has this issue. Some languages go to various lengths to
'help' get around it (like C#).

Its not just a problem of Interfaces either.

Though what you describe as wanting, is Multiple Implementation
Inheritance , not Multiple Interface Inheritance .
 
O

Oliver Wong

Andrew McDonagh said:
But... interfaces do not specify WHAT the method does, just that there is
a public method with that signature on that TYPE of object.

Yes, from the compiler's point of view, this is what interfaces mean.
Just like there is nothing syntactically wrong with using "for (x = y;;) {}"
to assign the value of y to x. But from a design point of view, interfaces
DO specify "WHAT" a method does; what it doesn't specify is HOW it does it.

Take for example a random interface from the Java API library:
java.lang.Comparable. Read the JavaDocs for the methods it defines, and
you'll note that the person who designed this interface very explicitly
writes WHAT the interface is supposed to do:

compareTo(T o): Compares this object with the specified object for order.

Note that it doesn't specify HOW to implement the method, only WHAT the
method does. How the method is implemented lies in the body of the method,
which would appear in a class implementing the interface.
This problem is not just limited to Java, any language that supports
Polymorphism has this issue. Some languages go to various lengths to
'help' get around it (like C#).

Its not just a problem of Interfaces either.

Though what you describe as wanting, is Multiple Implementation
Inheritance , not Multiple Interface Inheritance .

Call it what you want, Java doesn't have a solution for this problem and
C# does. And I don't particularly like C#, so I'm hoping that Sun will
implement a solution (maybe C#'s solution, maybe some other solution) in
their next version of Java.

- Oliver
 
J

jan V

So all in all, unless my prediction of trouble ahead is flawed, I think
you
I fail to see your point.
If Sun suddently changed the signature or function of, say,
java.awt.Component,

Who's talking about changing any method signatures? That's not what I said,
I wrote "reimplementing [methods], possibly with their functionality subtly
changed".. in other words I'm talking about the precise semantics of a
method being subtly changed. The method signature isn't touched at all.

The problem with your scheme is that

a) you pick arbitrary methods from abstract/concrete classes which are not
the subject of any interface contracts written by the same authors of the
classes

b) you define an interface which contains those same methods (as signatures
only, obviously), and by doing so you "freeze" a particular *semantic
contract* for these methods

c) you now subclass a third-party class (Sun's), and impose on this class
your interface's contract.

From now on, any future changes to the *precise semantics* of the methods
you picked, as altered or enhanced or rewritten by Sun, may very likely
break your scheme.

Why? Because Sun don't know or care about your interface's rigid semantic
contract, but you do... and suddenly the methods you tagged as "belonging"
to your interface don't match the semantics you imposed on them. The Sun
changes lead to a branching in semantics for these methods: one branch for
Sun's semantics, and one branch for your interface's semantics. Now guess
who's going to loose the battle of this splitting evolution? You, not Sun,
since Sun aren't even aware some clever guy decided to try to impose a
semantic straightjacket on a subset of Component methods....
So i am resting quite assured that it won't happen.

Do you understand the scenario now?
 
O

Oliver Wong

jan V said:
Who's talking about changing any method signatures? That's not what I
said,
I wrote "reimplementing [methods], possibly with their functionality
subtly
changed".. in other words I'm talking about the precise semantics of a
method being subtly changed. The method signature isn't touched at all.

The problem with your scheme is that

a) you pick arbitrary methods from abstract/concrete classes which are not
the subject of any interface contracts written by the same authors of the
classes

b) you define an interface which contains those same methods (as
signatures
only, obviously), and by doing so you "freeze" a particular *semantic
contract* for these methods

c) you now subclass a third-party class (Sun's), and impose on this class
your interface's contract.

From now on, any future changes to the *precise semantics* of the methods
you picked, as altered or enhanced or rewritten by Sun, may very likely
break your scheme.

Why? Because Sun don't know or care about your interface's rigid semantic
contract, but you do... and suddenly the methods you tagged as "belonging"
to your interface don't match the semantics you imposed on them. The Sun
changes lead to a branching in semantics for these methods: one branch for
Sun's semantics, and one branch for your interface's semantics. Now guess
who's going to loose the battle of this splitting evolution? You, not Sun,
since Sun aren't even aware some clever guy decided to try to impose a
semantic straightjacket on a subset of Component methods....
So i am resting quite assured that it won't happen.

Do you understand the scenario now?

I'm not sure I understand how this is primarily a "bad use of interface"
problem as opposed to a "depending on undocumented behaviour" problem. I
think you'd have the exact same problem if you used one of Sun's classes in
composition and depended on a particular behaviour; if Sun changed the
behaviour, your code wouldn't work anymore.

I'd imagine typically that if one were to create an interface for a
particular set of methods from one of Sun's classes, the documentation
explaining the semantics of those methods would pretty much be taken
straight from Sun's javadocs. Then the interface creates no new restrictions
on behaviour that weren't already publicly documented on Sun's site. If
instead, the documentation for the new Interface read "int compareTo(Object
o): Compares this object with the specified object for order. Additionally,
computes the cube root of the hashcode of object o." then I don't think the
problem lies with Interfaces per say, but rather is more of a fundamental
misunderstanding of design-by-contract.

And if Sun changes documented behaviour, you can be sure a lot of people
will get upset.

- Oliver
 
J

jan V

I'm not sure I understand how this is primarily a "bad use of
interface"
problem as opposed to a "depending on undocumented behaviour" problem. I

Not even necessarily "undocumented behaviour". How many times have you seen
the latest JDK release notes state in the incompatible changes section
"method x was broken in our previous releases. It has now been reimplemented
to do X, and X is from now on the official documentation for that method x."
? In an ideal world that would never happen, but we live in a far-from ideal
reality...
think you'd have the exact same problem if you used one of Sun's classes in
composition and depended on a particular behaviour; if Sun changed the
behaviour, your code wouldn't work anymore.

Of course, but the OP will compound the problem by creating an interface at
the *top* of a hierarchy... breaking everything downstream if Sun fiddles
the semantics of one of "his" methods. That's at least as bad as some
regression bugs due to delegating (composition) to objects whose behaviour
have subtly changed from one JDK release to the next.
I'd imagine typically that if one were to create an interface for a
particular set of methods from one of Sun's classes, the documentation
explaining the semantics of those methods would pretty much be taken
straight from Sun's javadocs. Then the interface creates no new restrictions
on behaviour that weren't already publicly documented on Sun's site.

True, true, but the OP is not the prime maintainer of those semantics and
their documentation... Sun is. And that's the whole problem. Nobody can just
take snapshots of implementations by way of declaring an interface for
existing core API methods, and expect third parties like Sun to suddenly
honour those frozen semantics for the rest of time.

Right, I think I flogged my explanation to death... you either get it or you
don't... I gave it my best shot :)
 
C

Chris Berg

Erm... no, they don't have anything to do with anonymous inner classes.
Yes lots of examples use anonymous inner classes derived from Adapters,
but thats completely separate.

I don't say that adapters are the only use of anonymouse inner
classes, I'm saying the opposite: If not for use as a superclass for
an anonymous inner-class, I find it difficult to justify sub-classing
an adapter. Most of the listener interfaces - if not all - have very
few methods, and implementing them explicitly as empty {} is a good
way of 'documenting' that you intentionally left them as such.

Still, that's my opinion, not the definite truth.
Do you use (non static) inner classes?

Of course, but named inner classes as opposed to 'normal' classes, in
my opinion, have a different use, namely to limit the scope. Or am I
missing something?
 
A

Andrew McDonagh

Chris said:
I don't say that adapters are the only use of anonymouse inner
classes,

I didn't say you did.

you said ..

"I hardly ever use Adapters. They are mainly there to support anonymous
inner classes, which is a quick (and dirty?) way of creating a
Listener on-the-fly."

And I said 'they have nothing to do with anonymous inner classes.'

Now I'm not saying anything about whether people use anonymous inner
classes for adapters or not - just stating that inner classes have zero
to do with Adapters.

Adapters also have nothing to do with Listeners - aside from the fact
that its a 'common' usage - but not the only usage.

I'm saying the opposite: If not for use as a superclass for
an anonymous inner-class, I find it difficult to justify sub-classing
an adapter.

Well thats strange, seeing as the entire reason for this idiom is to
provide an Abstract baseclass that fulfills the interface specified by
either the Abstract class the Adapter derives from, or the Interface it
implements.

Lets take the usual example of MouseAdapter...

public abstract class MouseAdapter

http://java.sun.com/j2se/1.4.2/docs/api/java/awt/event/MouseAdapter.html

Its an Abstract class even though it fully satisfies the MouseListener
Interface - purely so that we have to Subclass it to add our own
overridden behavior to 0,1 or * of the methods.

Most of the listener interfaces - if not all - have very
few methods, and implementing them explicitly as empty {} is a good
way of 'documenting' that you intentionally left them as such.

Still, that's my opinion, not the definite truth.




Of course, but named inner classes as opposed to 'normal' classes, in
my opinion, have a different use, namely to limit the scope. Or am I
missing something?

An Anonymous class is the same as an Inner (nested) class (albeit with
some extra implicit constraints as in: never Abstract or Static and
always Final).

"...An anonymous class is always an inner class (§8.1.2);..."
http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#252986

they are purely a mechanism for declaring nested classes which we care
to to name - nothing more.
 
R

Raymond DeCampo

Andrew said:
Well thats strange, seeing as the entire reason for this idiom is to
provide an Abstract baseclass that fulfills the interface specified by
either the Abstract class the Adapter derives from, or the Interface it
implements.

Lets take the usual example of MouseAdapter...

public abstract class MouseAdapter

http://java.sun.com/j2se/1.4.2/docs/api/java/awt/event/MouseAdapter.html

Its an Abstract class even though it fully satisfies the MouseListener
Interface - purely so that we have to Subclass it to add our own
overridden behavior to 0,1 or * of the methods.

Another reason to subclass Adapter classes is that future versions of
the API might add to the interface. If you have extended the Adapter
class, then you have nothing to change.

Ray
 
C

Chris Berg

Another reason to subclass Adapter classes is that future versions of
the API might add to the interface. If you have extended the Adapter
class, then you have nothing to change.

Ray

Now THAT's a good point, I've never thought of that aspect.
 
C

Chris Berg

"...An anonymous class is always an inner class (§8.1.2);..."
http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#252986

they are purely a mechanism for declaring nested classes which we care
to to name - nothing more.

This discussion is an example of what very often happens in these
forums: Not only does the subject swing into something that is
irrelevant for the original post, but also two 'combattants' argue in
different directions, never being able to arrive at any common ground.

Your arguments are strictly technical, mine are concerned with
programming style. (If you don't agree, then re-read my original
post).

Of course you are right in saying that anonymous inner classes have
nothing to do with Adapters, from a _technical_ point of view, but
nonetheless the superclass of an a.i.c. is often an Adapter, and I
guess this use was what Sun had in mind when they invented them. In
Sun's own documentation you frequently meet examples of just that.
 
C

Chris Smith

Daniel Dyer said:
I didn't know that C# did things differently in this respect. I'm not
sure I like it, it would appear that you can change the observed behaviour
of the object just by casting. It reminds me of multiple inheritance in
C++.

I also didn't know C# did things differently in this respect... but I am
absolutely 100% sure that I like it. This is a huge conceptual problem
with the Java programming language (and many others as well). Java goes
to great lengths to prevent collisions of class names, and does a good
job of it. But then the approach to polymorphism defines a new global
namespace -- method names -- that have no such controls.

Fortunately, this is less of a problem in practice because method names
are practically isolated by inheritance subtrees. IMO that doesn't make
the poor design worthwhile.

I'm not familiar with C# at all in this case, but the obvious fix for
Java has nothing at all to do with multiple inheritance. It only means
that method names are qualified by a type name. The default type name
for a newly defined method would be the current type, if the method is
newly declared; or the parent type, if the method overrides the
superclass. A syntax would be added, just like C# did, for specifying
the method's type name if it differs from the default. A method would
be resolved based on the compile-time type of a reference at dispatch.

This might have an incidental similarity to multiple inheritance in
terms of some side effects of reference types and casting, but it is NOT
multiple inheritance, any more than a station wagon becomes a pickup
truck if you write the letters "F150" on the back bumper.
In the second example, what happens if I do this:

t.MyFunction();

???

Does this result in a compile-time error because it's ambiguous or does it
prefer the I1 version because it is specified first in the extends list?

This would need to be defined by the language specification, of course.
The most helpful answer would be for the compiler to fail with an error
about ambiguous dispatch.

In any case, these changes are clearly not backward-compatible, so they
are very unlikely to be adopted into the Java programming language. We
all know that eventually Java will be replaced by something for new
projects, and that something will be the best shot for a good qualified
representation of method names.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top