Initial core port of "Squeak Traits"

Brian Rice water at
Fri Nov 18 17:22:46 PST 2005

On Nov 16, 2005, at 6:23 PM, Brian Rice wrote:

> Finally, this ported code doesn't tie in to anything else yet,  
> except that you can installServicesOn: to get the methods that are  
> on the traits onto some other object(s). I'll spend the next day or  
> two figuring out a manageable way to do that and also write up some  
> examples to illustrate. I think that I'll try a refactoring of the  
> collect:, select:, etc. protocol so that the fact that they are  
> shared between Collection and ReadStream is more obvious and maybe  
> eliminate some code that way.

As I proceed with the tying-in, I'm noticing some odd limits in the  
way this design can be used, although none of these limits are even  
possible to reach without multiple dispatch, so it's not a "true"  
problem per se. I'm going to explain this so that hopefully a better  
design or just a way that it makes sense occurs to me, and also so  
that you all understand.

Basically, the way that Trait objects work now, the services (methods  
to install) are an attribute / query done on a single Trait. Methods  
are defined as services with an `asServiceOn: macro which doesn't  
define the method but compiles the block it would expand to, and puts  
it in a dictionary keyed by the signature (selector + roles). In  
order to identify where the component fits in to the signature, the  
Trait object *itself* is used in the method definition, and then  
replaced with the target object when finally compiling it.

The consequence of this design is that you can perform multiple  
dispatch on any concrete objects, plus any number of uses of the  
Trait itself, so a binary = method that dispatches to the same type  
on both sides is possible. HOWEVER, use of a different Trait object  
is not possible yet.

Also, the composition factor adds in a problem where the identity of  
the component is showing up as a placeholder in the top-level  
composition. So if you have A = B + C, then B and C's method are  
using B and C as placeholders, but my method of composing services  
doesn't replace the use of B and C with the use of A. I could do  
that, OR I could solve both problems at once by having every use of a  
Trait object in any signature at all go through a substitution  
process at the final moment of installation. But even then I have to  
know that B and C should translate to the same thing that A is trying  
to install to, whereas Trait objects used but found elsewhere  
should... I don't know, right now I'm leaning towards throwing an  
error and figuring out a sensible resolution later.

One solution I had considered was to somehow make services query  
methods that could be dispatched on multiple objects, so that  
interactions could be defined. But this seems complicated and nebulous.

On the other hand, having written this explanation now, raising it as  
an error does seem like a viable option, just to say "I wasn't  
composed of this Trait, so it doesn't resolve with me - figure out  
what it should be yourself".

Does this make sense to anyone? Are there conclusions reached here  
that don't make sense or could make more sense given a change in  
perspective? Let me know so I get a better perspective on all of this.



More information about the Slate mailing list