Initial core port of "Squeak Traits"
Brian Rice
water at tunes.org
Wed Nov 16 18:23:38 PST 2005
Here's something I've been thinking about for months but only coded
up this week. Squeak Traits is research that started on Squeak but
the idea has spread to a few other languages - I'm sure that many of
you on this list are likely to have run into it already, and maybe
some have tried it.
The original research homepage is here:
http://www.iam.unibe.ch/~scg/Research/Traits/
The source code for the port is in src/lib/trait.slate and is just a
few pages including comments:
http://slate.tunes.org/repos/main/src/lib/trait.slate
Note: The Slate code is not a direct port of the Squeak code - I
found that to be less clear than it ought to be, so I basically wrote
it according to the specification given in the research papers.
The base prototype is "Trait" to distinguish it from the objects we
access as "traits" and to emphasize that it is a component.
Essentially these things wrap "services" as an analogue of the
"method dictionary" idea found in single-dispatch languages; the
services are a dictionary from Signatures (selector plus roles) to
methods. The basic idea is that you sum (+) these components if you
want a disjoint union, or exclude certain methods using #-. You can
layer them linearly with "a ** b" so that b overrides a's services,
although "b over: a" might be easier to read; the overlay is good for
resolving the conflicts possible with +. There is also a crude way to
alias the methods of one component so they are not shadowed, using "a
aliasing: map" where the map goes from new signatures to old ones.
Anyway, the idea is that you can take a ton of small components and
assemble them independently, then run built-in checks for conflicts,
and this all acts as a declarative description which you can finally
compile into a single traits object or traits+prototype. The recent
method-send query extensions (allSelectorsSent*) were included so
that these checks would run better.
Why does Slate need this, you ask? Well, Smalltalk-80 needed this
more acutely because it buys its users a safe multiple inheritance
system where they only had single inheritance. We do have a mostly-
safe multiple inheritance system with our traitsWindow that linearly
orders super-types and we can change that order per type no matter
how it's inherited, but this is hard to manage and the delegations
are still traversed dynamically. Basically it doesn't scale up to the
ideal where every independent protocol you might want to re-use is a
separate cluster of methods. So this buys us some ability to deal
with bigger inheritance compositions safely. The existing system
won't go away, but we won't have to use it for protocol composition
nearly as much, especially where these protocols are truly static.
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.
--
-Brian
http://tunes.org/~water/brice.vcf
More information about the Slate
mailing list