"Syntax for Efficient Traits" is now ready for discussion (was: Classes as Sugar is...)

Tom Van Cutsem tomvc.be at gmail.com
Tue Sep 14 14:39:21 PDT 2010


>
> Hm, "function for making trait", "trait itself". Too many things. It may
>> bring complexity. Yes, i thought (and see in other languages, the same Ruby)
>> that Enumerable is a trait itself, and not a special (non-needed to me)
>> function. A user needed just a trait, not a function + trait.
>>
>
>  Please check out <http://traitsjs.org/>. The notion of traits there and
> in this strawman is the "stateful traits" approach that Tom first explained
> at <http://prog.vub.ac.be/Publications/2009/vub-prog-tr-09-04.pdf>. Until
> I saw this paper, I had written traits off as a dead end.
>
>
> It seems something interesting there, thanks, I'll take a look on the paper
> (as well as on all examples on the site). However, I'm aware that concept of
> a "trait" in contrast of a "mixin" has no state to avoid conflicts.
>

It is true that original traits are always stateless. This is not so much to
avoid name conflicts as to avoid the whole problem of diamond inheritance
(duplicate state inherited via different inheritance paths, cf. C++'s
virtual inheritance). On the other hand, stateless traits have their
drawbacks: you need to pollute a trait's public API with getter/setter
methods to 'fake' state.

The key idea behind the Traits discussed here and in that paper is that they
are 'generative': you generate them by calling a function that returns new
traits. This allows these traits to capture lexically visible state (usually
the arguments of the generator function). Using this approach you can make
stateful traits, and apart from instantiation issues (see below), there is
no need to distinguish a class from a trait anymore.


> I'm still not sure I understand you correctly. But if I do, Override is
> your vertical composition and Compose is your horizontal composition. Via
> Object.create, one can also mix traits with vertical composition using the
> JavaScript prototype chain. But then unbound inherited methods become
> observable, leading to all the normal confusions. By using only Override for
> vertical composition, only bound methods are observable. (This is like the
> old "binding on extraction" property of old ES4 classes.)
>
>
>
> Yes, regarding the end state of an object (via override/composition) you
> understand it correctly. But I meant exactly delegation based inheritance
> and asked -- why do you have (propose) a scheme where an object will have
> /own/ properties but not inherited? In Ruby as I showed, if we change
> Enumerable module (read Enumerable trait/mixin) by adding a new method
> "new_method" then the instance "things" of the class "MyCollection"
> automatically via delegation has access to the new method.
>
> And regarding classes, I think it's not acceptable not to have inheritance
> and to create also own properties. Even if will be a good VM optimization,
> the dynamics of the languages is lost -- if we add a new method to a class
> -- will all instances see this new method? That exactly I'm asking.
>

Ruby's modules and instance-class relationships indeed work via delegation
and enable changes to all live instances by changing modules/classes, and
per-instance customization. OTOH, because they chain together
objects/classes/modules via delegation instead of flattening the properties,
they don't provide the early conflict detection properties of traits. I
think you can get either one or the other, but not both from 1 language
feature. Javascript already has prototype delegation. Adding traits would
allow us to express object composition in different ways, with different
tradeoffs.


>
>   Just to clarify and not to confuse terminology/meanings, do I understand
> correctly: "low integrity " -- non-|this|-bounded inherited functions, and
> "high integrity" -- vice-versa -- statically bound |this| and own
> properties? Thanks.
>

I think this is the case + low-integrity = non-frozen object and high
integrity = frozen object.


> By the way, the phrase "a trait instantiate" in general case contradicts to
> traits concept. Because in many (all?) implementations and some general
> definitions of traits -- traits in contrast with classes cannot instantiate
> objects. They are just additional modules (to add small traits for the
> instance).
>

Indeed, for original traits, "instantiating a trait" makes little sense.
Original traits need classes to provide state. As indicated above,
generative traits can capture state, and if they don't have any missing
required properties, it could make sense to instantiate them.

In MarkM's proposal, a "trait class" is a function that, when called,
returns a property descriptor map. A "class" is a function that, when
called, returns an object created from a property descriptor map. While
technically you can "instantiate" a trait by calling a trait class function,
you will end up with a property descriptor map, not an instance. From the
end-user's point of view, it still only makes sense to instantiate class
functions.

Cheers,
Tom
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20100914/82a44df2/attachment.html>


More information about the es-discuss mailing list