Traits vs. Interfaces (was Re: election details *PLEASE READ*)
J J
azreal1977 at hotmail.com
Sat Feb 24 08:23:06 UTC 2007
>From: Andreas Raab <andreas.raab at gmx.de>
>Reply-To: The general-purpose Squeak developers
>list<squeak-dev at lists.squeakfoundation.org>
>To: The general-purpose Squeak developers
>list<squeak-dev at lists.squeakfoundation.org>
>Subject: Re: election details *PLEASE READ*
>Date: Fri, 23 Feb 2007 22:35:35 -0800
>
>The main problem is the (mostly) static nature of interfaces in Java. E.g.,
>declaring them is a pain, otherwise I would disagree. If you want to share
>a default implementation use a subclass - one of the big problems I see
>with traits is that their interfaces get so specific that an *alternative*
>implementation becomes effectively impossible (therefore completely loosing
>the point about interfaces as abstractions).
Does it have to be this way, or are you looking at a... less then optimal
use of a workable technology.
You asked before if I had used traits, and of course I haven't. I haven't
felt the need to reach for them so far, and I am under the impression that
the tools aren't ready anyway.
But I have used Type classes in Haskell which is where I am taking my
vantage point from. For those who may not know, type classes just specify a
specific "interface" (set of functions), and any type that wants to be in
that type class must provide an implementation. The class definition can
specify default implementations. For example:
class Eq where
(==) lhs rhs = not (lhs != rhs)
(!=) lhs rhs = not (lhs == rhs)
Now, as you notice, the definitions of those functions seem to depend on
each other. The compiler would detect this and make an error, of course, if
someone tried to use them both. It is simply a way to ensure that an
instance must supply either one, but they don't have to supply both.
For me, this provides everything that Java interfaces do (including type
safety. You can say e.g. my new function works on any type, so long as it
implements the Eq class) and more, since the default implementation avoids
so much code duplication [1].
I hear what you are saying about "use a base class", but does my base class
still have to say "implements"?
Either way, this feels to me like another manifestation of a problem I
always had with Java: implementation inheritance. I may make 3 totally
different window widgets, and by rights each one would "implement" a draw
API, but I will have to invent another class for them all to inherit to
avoid duplicating a bunch of unrelated code. People reading my code may
wonder why "3DGameWindow" is in the same tree as "TaskBarClockWidget", but
it is just to save code duplication.
This is what I have hopes that Traits can help me avoid. I only inherit
when there is an inheritance relationship present, and Traits are for the
code that is in common but only as a coincidence (e.g. a car and a plane can
both drive on a street, but the only thing I see in common are the wheels).
Personally my inheritance trees never get very deep. Normally just one
level down.
>For example, look at TAccessingMethodDictDescription (which is simply the
>first in the browser) - it is practically impossible to reimplement this
>(or any other) of the current traits for the class kernel in any way that
>doesn't exactly follow the current implementation (like if TAMD is
>responsible for accessing the method dictionary then we should be able to
>reimplement MD access without affecting any other trait, right?).
Is this a problem with the technology (Traits), or the implementation?
>As I see it, there are *way* too many dependencies between these traits and
>interfaces can help to abstract from these dependencies. For sharing
>(default or not) implementation, Java (as well as Squeak) has a single
>inheritance tree which works for almost all purposes just fine. If you use
>delegation instead of inheritance it works for *everything* just fine and,
>IMO, typically results in a better set of collaborators because suddenly
>these roles become objects themselves.
Well that is a good technique. I don't personally see Traits as hammer or a
silver bullet, but I do think they (at least have potential to) fill a hole
[1].
>Early on I thought the same way (and this was why we started thinking down
>that road when Nathanael interned with us). However, in practice it seems
>like Traits are mostly being used as a thinly veiled version of MI with all
>the same problems. You have correctly pointed out that Java interfaces are
>"nothing but abstract virtual base classes in C++" - which coincidentally,
>was the only way that MI ever worked in C++, which itself has two dozen
>ways of doing MI wrong and exactly ONE to do it right (abstract virtual
>base classes).
Well, C++ was my favorite language for a long time (before I met Smalltalk
:), and I have used it quite a bit. And I couldn't agree more. The only
useful purpose I ever saw MI serve was just what you said.
And this is one thing I am paying attention to with the Traits stuff. There
has been talk of adding variables to Traits and I (strongly) disagree with
this idea. At that point, IMO it Traits would just be brining in MI through
the back door. What I always think when I, or anyone else, came up with the
need to do MI is "rethink the design". In every case I have ever seen, some
other pattern has always been a better choice.
But since Traits can't have variables, I would expect them to be useful in
many of the same ways Haskell type classes are. I could be wrong, but I
hope I'm not and I can't think of a technical reason Traits must create
fragility.
>Java choose a stand on that and it worked (which is pretty impressive given
>that it was the first language that used interface to that extent). Traits
>seem to reintroduce a number of ways of using MI wrongly (at least that's
>the feeling that I get when I look at the practical example) and that's why
>I prefer interfaces.
I understand your concerns. I never want to see Smalltalk go down the MI
road either. But for me, the presence of variables is what differentiates
between MI and "interfaces with default implementations".
My point of view comes from seeing a system that has this and seems to work
very well. I don't know what your experiences are, but if it's limited to
C++ then I don't wonder at your skepticism. :)
But I also wonder if it is sort of a "hot button" issue. I mean, there are
things to be frustrated/embarrassed about here (e.g. releasing something
into the image that appears to have no means of maintaining).
[1] Imagine the situation you would be in in Java if all class that can be
compared for equality must implement this interface! Every single class
that implemented the interface would have one of those two functions just be
a "not" of the other. And I don't think your solution of making a base
class is going to work here because we may also want classes like Ord (less
than, greater than) and so on. You would need a base class for every
possible combination.
Of course the solution is to not have such a class, but is this the right
solution? Shouldn't we have some fine grained reflective way of knowing if
the class supports a specific protocol like equality?
_________________________________________________________________
Refi Now: Rates near 39yr lows! $430,000 Mortgage for $1,399/mo - Calculate
new payment
http://www.lowermybills.com/lre/index.jsp?sourceid=lmb-9632-17727&moid=7581
More information about the Squeak-dev
mailing list
|