[Traits] questions/comments

Nathanael Schärli n.schaerli at gmx.net
Tue Feb 25 15:14:11 UTC 2003


Hi German

Thanks for your interest in traits and asking these interesting
questions. Here are the answers:

> -I see how the conflict resolution is applied for provided 
> methods, but not for required methods. The same aliases 
> mechanism is applied?

First of all, it is to say that combining multiple traits that require
the same method do not cause a conflict. This means that the
requirements are just unified and can then be satisfied by implementing
the required selector.

Since you asked about aliasing of required selectors, I figure that you
are imagining the case where you want to combine two traits A and B
which both have a requirement foo, and you want tho satisfy these
requirements with two different methods (i.e., A>>foo should not be the
same as B>>foo). 

Unfortunately, this is not possible in the current version of traits.
I'm sure you don't like to hear that, and to tell you the truth, I don't
like it myself and that's one of the reasons why I'm working on an
extended traits model (i.e., traits v2) now :-).

Also traits v1 can therefore not be used in a situation as pointed out
above, this limitation is actually less severe than you might think
because it does not appear so often in practice. (Most of the times,
requirements for different implementations also have different names).
In addition, it is important to understand that also all the other forms
of mixins in Smalltalk suffer from the exact same limitation. The cause
of this problem is that Smalltalk does not provide any kind of
encapsulation/visibility mechanisms, but I'll come back to this issue
later.

However, a straight-forward implementation of encapsulation/visibility
does not necessarily solve this problem. A good example is Java, which
does not provide any solution for the above problem either. The crux is
that the Java encapsulation/visibility mechanisms (i.e., public,
protected, private) are not fine-grained enough for this kind of
situation. This means that if you have two interfaces A and B which both
require a method foo, these requirements get always unified and there is
no way a class can implement a different version of foo for the two
interfaces!

Basically, there are two different solutions to this problem:

a) Consistent renaming. This means that each usage of foo in A is
renamed to let's say fooA and each usage of foo in B is renamed to let's
say fooB)

b) A good encapsulation/visibility mechanism. This means that we could
actually say that the requirements for foo in A and B are encapsulated
and therefore don't conflict in the class that combines A and B.

The problem with a) is the fact that this kind of renaming, especially
when applied extensively, can make it really hard to understand the
resulting code (in fact, it completely invalidates the flattening
property). And because I don't like having such "dangerous mechanisms"
if not absolutely necessary I decided against it.

Solution b) is less problematic. However, in order to do it right, I
want to introduce a visibility/encapsulation mechanism that can not only
be used for traits, but for regular ST classes in general. (Finally, we
have the exact same problem already in traditional Smalltalk, becaus it
is not possible to reuse a name in a subclass without affecting the
meaning of the superclass). Also this solution tends to have negative
impact on the flattening property, but we believe that we have found a
nice way so that it only has minimal impact on it!

However, introducing such a mechanism into ST is not all trivial.
Especially because I would like to have backwards compatibility, and I
don't at all like the keyword based approaches in other languages (i.e.,
private, public, protected, etc.). Thus, I decided against incorporating
this mechanism into the first version of traits. It would simply have
been too much and so I preferred going step by step: First having a very
simple version that just introduces the idea of traits (v1), and then
having a version that makes traits muh more powerful and also gets rid
of some other limitations in ST (v2).

> -I don't completely like the Substraction mechanism (TDrawing 
> - {#hash}). It seems to me that it leads to the same problem 
> described in "Fragile hierarchies". For example, in the 
> example of Circle composed with TCircle and TDrawing - 
> {#hash, #= and #~=}, if later TEquality adds a new method 
> #?=, Circle will have a conflict. Perhaps instead of:  Circle 
> = TCircle + (TDrawing - {#hash, #= and #~=}) I would prefer:  
> Circle = TCircle + (TDrawing - TEquality) ???

Also here I can exactly see what you mean. In fact, I was having the
exact same thought and the current prototype implementation actually
still allows to subtract whole subtraits rather than individual methods.

The reason why I finally decided to take this out is that writing
somethin like 

Circle = TCircle + (TDrawing - TEquality)

exposes details about the implementation of the trait TDrawing to the
outside. This means that if the implementor of TDrawing would later on
decide to implement #=, #hash and #~= directly in the trait TDrawing
rather than in a subtrait TEquality, this code would brake also the
semantics of TDrawing is exactly the same as before!

Nevertheless, I agree with you that a concept like that would be very
interesting and definitely had some nice advantages over specifying the
excluded selectors one by one. And again, I have good news for you: We
already have a solution for this problem that provides all the
advantages of the approach you suggested and still does not expose
details about the trait implementetions. 

In fact, one of the key concepts of trait v2 is that we intrdoduce a
notion of first-class interfaces/roles. And the nicest thing is that
this notion also solves the problem with encapsulation/visibility that I
pointed out above.

> -a final small comment: I like what I'm reading.

Thanks!

Well, after writing this email I'm more than ever eager to get started
with implementing the extended traits model. I can't wait until I can
play with it.

Cheers,
Nathanael




> -----Original Message-----
> From: squeak-dev-bounces at lists.squeakfoundation.org 
> [mailto:squeak-dev-bounces at lists.squeakfoundation.org] On 
> Behalf Of German Morales
> Sent: Dienstag, 25. Februar 2003 14:48
> To: squeak-dev at lists.squeakfoundation.org
> Subject: [Traits] questions/comments
> 
> 
> Hi everybody, specially traits people at Bern,
> 
> I'm reading the very interesting Traits papers, and although 
> I haven't finished reading, I can't resist to ask some 
> questions and give some
> comments:
> 
> -I see how the conflict resolution is applied for provided 
> methods, but not for required methods. The same aliases 
> mechanism is applied?
> 
> -I don't completely like the Substraction mechanism (TDrawing 
> - {#hash}). It seems to me that it leads to the same problem 
> described in "Fragile hierarchies". For example, in the 
> example of Circle composed with TCircle and TDrawing - 
> {#hash, #= and #~=}, if later TEquality adds a new method 
> #?=, Circle will have a conflict. Perhaps instead of:  Circle 
> = TCircle + (TDrawing - {#hash, #= and #~=}) I would prefer:  
> Circle = TCircle + (TDrawing - TEquality) ???
> 
> -a final small comment: I like what I'm reading.
> 
> That's all for the time being. I'll try to finish reading the 
> papers. I mean, if you want to answer "that is explained 
> later in the other paper!!!", feel free to do it ;-)
> 
> Regards,
> 
> German Morales
> 
> 
> 
> 



More information about the Squeak-dev mailing list