Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Traits: to renew OO inheritance in a hacker style discussion

7 views
Skip to first unread message

Dmitry Dorofeev

unread,
Feb 12, 2004, 8:14:11 AM2/12/04
to perl6-l...@perl.org
Hi all,

I see that i am not alone in my thoughts about classic OO drawbacks.
Some smart people created traits for SmallTalk which is something
close to what i want.

Traits are mechanism, recently proposed by Scharli et al, for factoring Smalltalk class hierarchies. By separating the issue of code reuse from the inheritance hierarchy, traits allow one to avoid problems with methods defined too high in the inheritance hierarchy while sharing common implementation. Early experience with traits in Smalltalk shows that traits are an effective way to improve code sharing in class hierarchies. This positive experience with traits in the untyped Smalltalk world suggests that traits may be useful in statically typed languages too.


Sch╗arli et al. recently proposed a mechanism called traits as a way to foster code reuse in objectoriented programs [SDNB03]. They have prototyped the mechanism in the context of the Squeak implementation of Smalltalk. Using traits, they refactored the Smalltalk collection classes achieving a 25% reduction in the number of method implementations and a 10% reduction in source code size [BSD03]. This early experience suggests that traits are a promising mechanism for factoring class hierarchies and supporting code reuse and may be useful for statically typed languages too. The main contribution of this paper is to present a typed calculus of traits that can serve as the foundation for integrating traits into a statically-typed object-oriented language such as JAVA [AG98] or Moby [FR99, FR03]. A trait is collection of named methods. In Smalltalk traits, these methods cannot directly reference instance variables; instead, they must be pure behavior. The methods defined in a tr
ait are called the provided methods, while any methods that are referenced, but not provided, are called required methods. An important property of traits is that while they help structure the implementation of classes, they do not affect the inheritance hierarchy. Traits are formed by definition (i.e., listing a collection of method definitions) or by using one of several trait operations:

Symmetric sum merges two disjoint traits to create a new trait.

Override forms a new trait by layering additional methods over an existing trait. This operation is an asymmetric sum. When one of the new methods has the same name as a method in the original trait, the override operation replaces the original method.

Alias creates a new trait by adding a new name for an existing method.

Exclusion forms a new trait by removing a method from an existing trait. [Urraaaah!]

Combining the alias and exclusion operations yields a renaming operation, although the renaming is shallow.

The other important operation on traits is inheritance, the mechanism whereby traits are integrated with classes. This operation merges a class C, a trait, and additional fields and methods to form a new subclass of C. Often, the additional methods provide access to the newly added fields. The additional methods, plus the methods inherited from C, provide the required methods of the trait. An important aspect of traits is that the methods of a trait are only loosely coupled; they can be removed and replaced by other implementations. In this way traits are a lighter-weight mechanism than either multiple inheritance or mixins.

grabbed from http://www.cs.uchicago.edu/research/publications/techreports/TR-2003-13
see also http://www.iam.unibe.ch/~schaerli/smalltalk/traits/traitsPrototype.htm
--------
Hope that it is something interesting for real Perl hackers who will make Perl 6 the
best language ever.

-Dmitry Dorofeev.

Aaron Sherman

unread,
Feb 12, 2004, 8:52:50 AM2/12/04
to Dmitry Dorofeev, Perl6 Language List
On Thu, 2004-02-12 at 08:14, Dmitry Dorofeev wrote:

> I see that i am not alone in my thoughts about classic OO drawbacks.
> Some smart people created traits for SmallTalk which is something
> close to what i want.

Perhaps I'm slow, but I don't see the difference between a trait and a
Java interface other than the fact that traits appear to be more of a
run-time construct.

Java interfaces are actually a very nice compromise between multiple and
single inheritance.

--
Aaron Sherman <a...@ajs.com>
Senior Systems Engineer and Toolsmith
"It's the sound of a satellite saying, 'get me down!'" -Shriekback

signature.asc

Dmitry Dorofeev

unread,
Feb 12, 2004, 9:56:58 AM2/12/04
to perl6-l...@perl.org
Aaron Sherman wrote:
>
> Perhaps I'm slow, but I don't see the difference between a trait and a
> Java interface other than the fact that traits appear to be more of a
> run-time construct.
>
> Java interfaces are actually a very nice compromise between multiple and
> single inheritance.

You can not get rid of the method with Java interface. Plus, interface is only
declaration, you must implement methods in each class which use interface.
AFAIK (last touched Java 5 years ago)

Look at example:
While the purpose of this paper is not to argue the merits of traits per se (see [SDNB03, BSD03] for such arguments), it is helpful to understand the motivation for traits. In languages with single inheritance, such as Smalltalk, it is often the case that inheritance does not provide sufficient flexibility for structuring a class hierarchy. Consider the case of two classes in different subtrees of the inheritance hierarchy and assume that they both implement some common protocol. If this protocol is not implemented by a common superclass, then each class must provide its own implementation, which results in code duplication. On the other hand, if we lift the implementation of the protocol up to the common superclass, we pollute the interface of the superclass, which affects all of its subclasses. Furthermore, if the protocol is defined by building on methods defined in intermediate classes, we will have to add these methods to the common superclass as well. This problem resul
ts from the dual nature of classes. Classes serve as both object generators and as superclasses. In the former case, the implementation of a class must be complete, whereas in the latter case the class implementation may have abstract methods that are implemented by a subclass. Traits provide a mechanism to separate these two aspects of classes and allow code to be reused across the class hierarchy. Multiple inheritance [Str94] and mixins [BC90, FKF98] represent two other attempts to solve this problem, but they both introduce semantic complexities and ambiguities (e.g., multiple copies of instance variables in the case of multiple inheritance, and problems with the order of method definition in the case of mixins) [SDNB03].

It is from link i provided in previous post.

-Dmitry Dorofeev.

>

Larry Wall

unread,
Feb 12, 2004, 12:38:47 PM2/12/04
to perl6-l...@perl.org
Yes, that's a very good paper, which is why Perl 6 now has something
called Roles, which are intended to degenerate either to Traits or
Interfaces. My take on it is that Roles' most important, er, role
will be to abstract out the decision to compose or delegate. But we'd
like them to function as interfaces when the Role is "abstract",
and we'd like them to function as Traits when you don't happen to
specify any state attributes. But for hiding the delegation decision,
you at least have to allow the amount of state that lets you remember
the object you're delegating to. Of course, the Traits paper didn't
go into traits with state, though it did mention it as a future research
topic. We're just doing that future research for them. :-)

By the way, we distinguish Traits from traits (which are compile-time
properties applied by "is". To apply a Role we use "does".

Larry

Chromatic

unread,
Feb 12, 2004, 2:03:57 PM2/12/04
to Aaron Sherman, Perl6 Language List
On Thu, 2004-02-12 at 05:52, Aaron Sherman wrote:

> Perhaps I'm slow, but I don't see the difference between a trait and a
> Java interface other than the fact that traits appear to be more of a
> run-time construct.

The easy answer is that interfaces completely suck while traits don't.
:)

Seriously though, Java interfaces add an alternate type system with an
alternate syntax for querying. They also don't allow any sort of
reasonable code re-use. Effectively, they're abstract
multiply-inheritable base classes with a different name because
"Multiple Inheritance Is Bad!"

On a conceptual level, the different syntax is the worst crime because
it reinforces the idea that the important question about an object is
"What is this object's position in a class hierarchy?", not "Does this
object have the same semantic meaning for these operations as I expect
it to have?"

Then again, I usually explain it in terms of "sucks", not "don't even
acknowledge the real problem".

-- c

Larry Wall

unread,
Feb 12, 2004, 2:49:02 PM2/12/04
to Perl6 Language List
On Thu, Feb 12, 2004 at 11:03:57AM -0800, chromatic wrote:
: On a conceptual level, the different syntax is the worst crime because

: it reinforces the idea that the important question about an object is
: "What is this object's position in a class hierarchy?", not "Does this
: object have the same semantic meaning for these operations as I expect
: it to have?"

What I'm currently thinking about is a "does" predicate that tells you
if an object/class does a particular role completely. If you pull
part of a role into a class, it returns false, because it doesn't do
the complete role. However, if you use "like" instead, it returns a
number between 0 and 1 telling you what fraction of the role's methods
it uses. So you can ask if your object is more like a Dog or a Tree.

Unless someone comes up with a better idea, of course. Obviously .does()
is redundant with .like() == 1. But it seems like a useful redundancy.

Larry

Chromatic

unread,
Feb 12, 2004, 3:02:50 PM2/12/04
to Larry Wall, Perl6 Language List
On Thu, 2004-02-12 at 11:49, Larry Wall wrote:

> What I'm currently thinking about is a "does" predicate that tells you
> if an object/class does a particular role completely. If you pull
> part of a role into a class, it returns false, because it doesn't do
> the complete role. However, if you use "like" instead, it returns a
> number between 0 and 1 telling you what fraction of the role's methods
> it uses. So you can ask if your object is more like a Dog or a Tree.

> Unless someone comes up with a better idea, of course. Obviously .does()
> is redundant with .like() == 1. But it seems like a useful redundancy.

Is it more useful to find the Dog-like-ness of a class or the notion
that SomeClass.bark() is semantically Dog-like, not Tree-like?

I expect to care more that the object does something Dog-like with the
methods I'm about to call on it than how Dog-like it is in general.
Maybe that's slicing does() way too thin, but like() seems to care an
awful lot about the implementation of how some class does some role.

-- c

Larry Wall

unread,
Feb 12, 2004, 3:15:52 PM2/12/04
to Perl6 Language List
On Thu, Feb 12, 2004 at 12:02:50PM -0800, chromatic wrote:
: Is it more useful to find the Dog-like-ness of a class or the notion

: that SomeClass.bark() is semantically Dog-like, not Tree-like?

I expect we'd use .can() for method-based queries.

: I expect to care more that the object does something Dog-like with the


: methods I'm about to call on it than how Dog-like it is in general.
: Maybe that's slicing does() way too thin, but like() seems to care an
: awful lot about the implementation of how some class does some role.

I only see like() as counting the methods available through the public
contract to determine its percentage. Something you could do by hand with
.can(). But there wouldn't be much point in putting it in if people
won't use it. On the other hand, if people want it and it's not there,
they'll reinvent it, poorly.

Larry

Robin Berjon

unread,
Feb 12, 2004, 3:19:56 PM2/12/04
to Larry Wall, Perl6 Language List
Larry Wall wrote:
> I only see like() as counting the methods available through the public
> contract to determine its percentage. Something you could do by hand with
> .can(). But there wouldn't be much point in putting it in if people
> won't use it. On the other hand, if people want it and it's not there,
> they'll reinvent it, poorly.

I'd use it for marshalling objects composed of many things to something
that makes sense to someone else's idea of what they should be, eg an
XML Schema. Pick what it's most alike to and marshall as that.

--
Robin Berjon

Jonathan Lang

unread,
Feb 12, 2004, 8:58:18 PM2/12/04
to Larry Wall, Perl6 Language List
Larry Wall wrote:
> What I'm currently thinking about is a "does" predicate that tells you
> if an object/class does a particular role completely. If you pull
> part of a role into a class, it returns false, because it doesn't do
> the complete role. However, if you use "like" instead, it returns a
> number between 0 and 1 telling you what fraction of the role's methods
> it uses. So you can ask if your object is more like a Dog or a Tree.
>
> Unless someone comes up with a better idea, of course. Obviously
> .does() is redundant with .like() == 1. But it seems like a useful
> redundancy.

I'd rather they not be redundant. Instead, C<does> would check to see if
the role in question is ever directly referenced anywhere in the class
definition (or in any of its parent class' definitions), whereas C<like>
would check to see how many of the methods and/or attributes supplied
and/or demanded by the role are available to the class. Thus, a class
that includes a C<bark> method but no C<Dog> role will return a not purely
false value for the C<like> predicate, but would return false for the
C<does> predicate. This would tell you that the class can bark, but not
neccessarily like a Dog. Whereas if it answers true to C<does>, you know
that when it barks, it will likely do so in the manner that a Dog does.

Furthermore, I have my doubts about how useful a zero-to-one number would
be as a return value for C<like>. Personally, I'd rather get a junction
of C<can> and C<has> predicate calls, which I could then query to find out
exactly how the class is C<like> the role in question, and how it differs.
That is,

C<$x like $y> :=
C<any($x »can« @methods($y)) or any($x »has« @attributes($y))>

or

C<all($x »can« @methods($y)) and all($x »has« @attributes($y))>

or maybe just

C<$x »can« @methods($y), $x »has« @attributes($y)>

=====
Jonathan "Dataweaver" Lang

__________________________________
Do you Yahoo!?
Yahoo! Finance: Get your refund fast by filing online.
http://taxes.yahoo.com/filing.html

Dmitry Dorofeev

unread,
Feb 13, 2004, 5:22:38 AM2/13/04
to perl6-l...@perl.org
Larry Wall wrote:
> Yes, that's a very good paper, which is why Perl 6 now has something
> called Roles, which are intended to degenerate either to Traits or
> Interfaces. My take on it is that Roles' most important, er, role
> will be to abstract out the decision to compose or delegate. But we'd
> like them to function as interfaces when the Role is "abstract",
> and we'd like them to function as Traits when you don't happen to
> specify any state attributes. But for hiding the delegation decision,
> you at least have to allow the amount of state that lets you remember
> the object you're delegating to. Of course, the Traits paper didn't
> go into traits with state, though it did mention it as a future research
> topic. We're just doing that future research for them. :-)

Perfect !

My stupid question still apply.
Will it be possible to have
'Exclusion' which forms a new trait|Role by removing a method from an existing trait|Role ?

or should I read some docs on Roles to be smarter ?
Thanks.
-Dmitry

Aaron Sherman

unread,
Feb 13, 2004, 2:02:11 PM2/13/04
to chromatic, Perl6 Language List
On Thu, 2004-02-12 at 14:03, chromatic wrote:
> On Thu, 2004-02-12 at 05:52, Aaron Sherman wrote:
>
> > Perhaps I'm slow, but I don't see the difference between a trait and a
> > Java interface other than the fact that traits appear to be more of a
> > run-time construct.
>
> The easy answer is that interfaces completely suck while traits don't.
> :)

Ok, so what you're saying is that they're solving for exactly the same
thing, but you don't like the Java implementation.

Cool, I just wanted to see if I understood what a trait was. Interfaces
are a great feature, IMHO, and if Perl 6 can implement them (as Larry
suggests) in an even more flexible and well integrated way (via roles),
I'm all for it.

Chromatic

unread,
Feb 13, 2004, 2:27:13 PM2/13/04
to Aaron Sherman, Perl6 Language List
On Fri, 2004-02-13 at 11:02, Aaron Sherman wrote:

> On Thu, 2004-02-12 at 14:03, chromatic wrote:

> > The easy answer is that interfaces completely suck while traits don't.
> > :)

> Ok, so what you're saying is that they're solving for exactly the same
> thing, but you don't like the Java implementation.

Yes and no. I don't think Java interfaces actually solve anything
except "let's not change the bytecode spec *again*". At least they
acknowledge that single-inheritance isn't the be-all end-all of objects,
but the second wrongest way to improve polymorphism is to add a second
type of polymorphism with a separate implementation, philosophy, and
syntax.

The first, of course, is just to ignore the problem.

The right way to improve polymorphism is to find common ground between
inheritance, delegation, composition, aggregation, and reimplementation,
make that your baseline, and support those techniques equally well.
That has implications for the type system, the core libraries, and
method dispatch, so it's much harder than copying an existing language
and throwing out the parts you don't like.

Then again, many things that are difficult are worth doing.

-- c

Larry Wall

unread,
Feb 16, 2004, 5:38:04 PM2/16/04
to perl6-l...@perl.org
On Fri, Feb 13, 2004 at 01:22:38PM +0300, Dmitry Dorofeev wrote:
: My stupid question still apply.

: Will it be possible to have
: 'Exclusion' which forms a new trait|Role by removing a method from an
: existing trait|Role ?

There will certainly be some way to exclude or at least hide the
method from a role. The trick is to prevent people from making
false assumptions about whether the object can bark just because
$object.does(Dog) returns true. Or maybe it's not that important,
if we can train people to rely on multiple dispatch to decide these
things.

: or should I read some docs on Roles to be smarter ?

Right after I finish writing them... :-)

Larry

Larry Wall

unread,
Feb 17, 2004, 11:30:36 AM2/17/04
to Perl6 Language List
On Thu, Feb 12, 2004 at 05:58:18PM -0800, Jonathan Lang wrote:
: Larry Wall wrote:
: > What I'm currently thinking about is a "does" predicate that tells you
: > if an object/class does a particular role completely. If you pull
: > part of a role into a class, it returns false, because it doesn't do
: > the complete role. However, if you use "like" instead, it returns a
: > number between 0 and 1 telling you what fraction of the role's methods
: > it uses. So you can ask if your object is more like a Dog or a Tree.
: >
: > Unless someone comes up with a better idea, of course. Obviously
: > .does() is redundant with .like() == 1. But it seems like a useful
: > redundancy.
:
: I'd rather they not be redundant. Instead, C<does> would check to see if
: the role in question is ever directly referenced anywhere in the class
: definition (or in any of its parent class' definitions), whereas C<like>
: would check to see how many of the methods and/or attributes supplied
: and/or demanded by the role are available to the class. Thus, a class
: that includes a C<bark> method but no C<Dog> role will return a not purely
: false value for the C<like> predicate, but would return false for the
: C<does> predicate. This would tell you that the class can bark, but not
: neccessarily like a Dog. Whereas if it answers true to C<does>, you know
: that when it barks, it will likely do so in the manner that a Dog does.

I think that would be the wrong approach, or at least, not quite
the right approach. If you're going to use all or part of the Dog
interface without the Dog implemention, you should still be relying on
the Dog role to define your interface. To oversimplify, you should
still have your class explicitly "do" Dog to pull in the interface,
but then override all the methods as if Dog were a pure Interface.

That is oversimplified because if Dog subsequently changes, you could
end up pulling in the new part of the Dog implementation by accident,
and it might not play well with your implementation of the interface.

So perhaps we need a different word than "does" to indicate that
you want to include the Dog interface without including the Dog
implementation. Perhaps we can do that with "is like(Dog)" or some
such if we don't want to Huffman code it shorter. Then people who
believe only in Interfaces can use the same underlying system-defined
Roles without compromising their Java-bedeviled value system. :-)

I think that your structural equivalence approach would be
harder to calculate and less likely to be correct. Perhaps we could
retain .like for named equivalence, and have a .resembles for
structural equivalence. But .resembles would have to do better
than merely comparing method names. If it doesn't also compare
type signatures, it'll be demonstrably incorrect. And if it does
compare type signatures, it'll be slower than .like, which can
rely on role names bound to method names at compile time.

Howsomever, if we do distinguish "does" from "like" at the caller end,
I'll go along with you far enough to agree that a .like predicate
should be more disjoint from a .does predicate, except insofar as
we should guarantee that $obj.like(Dog) >= $obj.does(Dog). That is,
if .does == 1, then certainly .like == 1. However, .does can drop
faster than .like, since it's constraints are stricter.

That's assuming that both .like and .does return 0 <= $x <= 1 in
numeric context. In a Boolean context you only get 0 or 1, with
intermediate values truncated to 0, since you can't guaranteed
the interface if any methods have been overridden, and I suspect
people are more interested in guarantees than probabilities.

: Furthermore, I have my doubts about how useful a zero-to-one number would


: be as a return value for C<like>. Personally, I'd rather get a junction
: of C<can> and C<has> predicate calls, which I could then query to find out
: exactly how the class is C<like> the role in question, and how it differs.
: That is,
:
: C<$x like $y> :=

: C<any($x ?can? @methods($y)) or any($x ?has? @attributes($y))>
:
: or
:
: C<all($x ?can? @methods($y)) and all($x ?has? @attributes($y))>
:
: or maybe just
:
: C<$x ?can? @methods($y), $x ?has? @attributes($y)>

That's certainly possible, but also almost certainly inefficient.
In general, the approach people will actually use is to just assume
you can call the method you want, and catch the exception if it fails.
In that case, it almost doesn't matter how we define .like or .does.
It's a bit like people checking their method invocants for the correct
"isa", when they should just rely on the dispatch mechanism to find
the appropriate method, or fail.

Larry

Dan Sugalski

unread,
Feb 17, 2004, 11:39:07 AM2/17/04
to Perl6 Language List
At 8:30 AM -0800 2/17/04, Larry Wall wrote:
>So perhaps we need a different word than "does" to indicate that
>you want to include the Dog interface without including the Dog
>implementation. Perhaps we can do that with "is like(Dog)" or some
>such if we don't want to Huffman code it shorter. Then people who
>believe only in Interfaces can use the same underlying system-defined
>Roles without compromising their Java-bedeviled value system. :-)

You could, I suppose, use "implements" to note that a class provides
the role all by itself, and "imports" to note that it brings in the
role from an external source.
--
Dan

--------------------------------------"it's like this"-------------------
Dan Sugalski even samurai
d...@sidhe.org have teddy bears and even
teddy bears get drunk

Larry Wall

unread,
Feb 17, 2004, 12:15:50 PM2/17/04
to Perl6 Language List
On Tue, Feb 17, 2004 at 11:39:07AM -0500, Dan Sugalski wrote:
: At 8:30 AM -0800 2/17/04, Larry Wall wrote:
: >So perhaps we need a different word than "does" to indicate that
: >you want to include the Dog interface without including the Dog
: >implementation. Perhaps we can do that with "is like(Dog)" or some
: >such if we don't want to Huffman code it shorter. Then people who
: >believe only in Interfaces can use the same underlying system-defined
: >Roles without compromising their Java-bedeviled value system. :-)
:
: You could, I suppose, use "implements" to note that a class provides
: the role all by itself, and "imports" to note that it brings in the
: role from an external source.

I think you are using the word "role" to mean "implementation".
I prefer to use "role" to mean both interface and implemention.
But I like your idea of using "implements" when you want to force
yourself to override the complete implementation, and it will make Java
programmers comfy. However, I still prefer "does" for pulling in the
complete role including both interface and implementation, in part
for Huffmanly reasons, but also to get the programmer concentrating
on the actual semantic relationships rather than the mechanism.
In other words, for the same reason Perl changes other C-ish words
to more natural English words:

C Perl
------ ------
switch given
case when
break last
continue next

Plus I think we should hold the "imports" notion in reserve for
talking about how to pull in bits of modules. It's okay to think
of "does" as a kind of fancy import or include, but I'd rather bias
the verbiage in favor of a more abstract view.

Larry

Dan Sugalski

unread,
Feb 17, 2004, 12:47:56 PM2/17/04
to Larry Wall, Perl6 Language List
At 9:15 AM -0800 2/17/04, Larry Wall wrote:
>On Tue, Feb 17, 2004 at 11:39:07AM -0500, Dan Sugalski wrote:
>: At 8:30 AM -0800 2/17/04, Larry Wall wrote:
>: >So perhaps we need a different word than "does" to indicate that
>: >you want to include the Dog interface without including the Dog
>: >implementation. Perhaps we can do that with "is like(Dog)" or some
>: >such if we don't want to Huffman code it shorter. Then people who
>: >believe only in Interfaces can use the same underlying system-defined
>: >Roles without compromising their Java-bedeviled value system. :-)
>:
>: You could, I suppose, use "implements" to note that a class provides
>: the role all by itself, and "imports" to note that it brings in the
>: role from an external source.
>
>I think you are using the word "role" to mean "implementation".
>I prefer to use "role" to mean both interface and implemention.

Well, I usually use role to mean the interface, but that's a separate
issue. (Implementation is, after all, just a matter of implementation)

I think it may be wise to separate the implementation and the
interface -- If I had to guess I'd say the declaration of interface
conformation is going to be a lot more common, at least in class
declarations.

Roles'll get thrown on individual variables and values, sure, but
when I'm writing a class (Yes, I know, but lets suspend disbelief for
a moment :) I'm not generally going to put a pre-existing role on a
class--I'll just inherit from the darned thing. Roles, when working
with whole classes, will be more a declaration of interface than an
importation of implementation. (That, I suppose, argues for two
separate sets of syntax, one for runtime role aquisition and another
for class definition, but I think I won't go there)

Either way I don't care what the keywords are, I just think that
there ought to be two, and it should be clear that interface and
implementation are different. Besides, *someone* will want to throw a
role on an object but use an alternate implementation. Think I won't
go there either, though.

Stéphane Payrard

unread,
Feb 19, 2004, 9:13:18 PM2/19/04
to perl6-l...@perl.org

In a sense, there is no such thing as state.

A read-only attribute is a role constituted of one getter method.
A write-only attribute is a role constituted of one setter
method. A read-write attribute is a role constituted of two
methods, one getter and one setter. A noread-nowrite attribute
could as well live in a parallel universe.

No attributes. It is turtles all the way down. :)

More seriously, the mere user of a class has no way to know if he
accesses a real attribute or a synthetic one. A synthetic
attribute being one that is calculated from real attributes or
whose modification affects other attributes. It may interesting
to provide syntax to declare the dependancies between attributes
even if there is no way to enforce them.

>
> Larry

Stevan Little

unread,
Feb 22, 2004, 2:34:05 PM2/22/04
to perl6-l...@perl.org
> A long time ago ... Dan said:

> Roles'll get thrown on individual variables and values, sure, but when
> I'm writing a class (Yes, I know, but lets suspend disbelief for a
> moment :) I'm not generally going to put a pre-existing role on a
> class--I'll just inherit from the darned thing. Roles, when working
> with whole classes, will be more a declaration of interface than an
> importation of implementation. (That, I suppose, argues for two
> separate sets of syntax, one for runtime role aquisition and another
> for class definition, but I think I won't go there)
>

Sorry for reviving an old thread here, but I am new to the list and I
wanted to comment on something Dan said here.

I have been working on a Perl 5 implementation of Traits, so I have
been reading and thinking about them a lot lately. I have been basing
much of my implementation and understanding of them off of this paper -
http://www.iam.unibe.ch/~scg/cgi-bin/oobib.cgi?
query=Traits+the+Formal+Model, which is a more formal model of Traits
than is described in either the initial traits paper or the one that
discusses the Smalltalk Collection refactoring. One thing that I
noticed was that the authors seem to not intend Traits to be thought of
as being like Classes. As a matter of fact they distinguish Traits from
Classes in their "Trait Language" (contained in the above paper). So
the idea of just being able to "inherit the darned thing", would not
work as a Trait is not a Class. Traits too are "flattened" into the
class that uses them, so there is no true inheritance there. Traits
themselves can be composed out of other traits though, but again the
flattening happens and no true inheritance exists.

But of course, Traits aren't Roles, and being new to the list, I am not
sure how much different they are to be. I will have to read back a ways
and see what was said. But I just wanted to put my 2 cents in here.

- steve

Chromatic

unread,
Feb 22, 2004, 4:16:11 PM2/22/04
to stevan little, p6l
On Sun, 2004-02-22 at 11:34, stevan little wrote:

> One thing that I noticed was that the authors seem to not intend
> Traits to be thought of as being like Classes. As a matter of fact
> they distinguish Traits from Classes in their "Trait Language"
> (contained in the above paper). So the idea of just being able to
> "inherit the darned thing", would not work as a Trait is not a Class.

Furthermore, roles are *not* inheritance. That's the point.
Inheritance is not the be-all, end-all of OO, and any system that tries
to fit everything into an inheritance-only model is irredeemably broken
from the start.

If inheritance always worked, we wouldn't need roles.

> Traits too are "flattened" into the class that uses them, so there is
> no true inheritance there. Traits themselves can be composed out of
> other traits though, but again the flattening happens and no true
> inheritance exists.

The goal of inheritance is not to fit the world into one hierarchy. The
goal of inheritance is to be able to write polymorphic code that does
the right thing and is reasonably sure that any object you receive
understands the method you're calling on it in the way that you intend.

Unsurprisingly, that's also the goal of delegation, aggregation,
composition, proxying, and reimplementation.

Inheritance is only one way to accomplish that. Sometimes it's the best
way. Many times, it's the worst way.

That suggests that there's some deeper truth underlying all of the other
polymorphic mechanisms. If that's true, you can build up all of those
other systems on top of this mechanism.

I think the base truth is roles, as seen in Perl 6.

Again, the goal is polymorphism. Inheritance is just a means to that
goal. If roles permit polymorphism separate from enforcing a particular
implementation of marking polymorphic equivalence as well as code
sharing, they'll be successful.

See Class::Roles on the CPAN for one implementation in Perl 5.

-- c

0 new messages