Initial core port of "Squeak Traits"
water at tunes.org
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