Traits library
Tom Van Cutsem
tomvc at google.com
Thu Feb 18 10:33:25 PST 2010
>
> For example, if you wanted to indicate whether a property should be
> documented you could do something like
>
{ a: Trait.document } where you would expand Trait to handle this new
> meta-data by doing something like
> Trait.compose(Trait, {'document': function() { ... }}). Match a new
> meta-data property with a Trait method of the same name
> would be one possible way of making Trait extensible in similar ways as
> java annotations. Given your expertise in this area,
> would you view this meta-circular approach as a way to extend Trait into
> areas beyond composition where
> more semantic behavior could be injected given a new meta-data keyword? You
> may feel this distorts the simple semantics
> but I would be interested in hearing your views.
>
Now I see what you're getting at. Interesting!
If you think of traits.js as a general-purpose property descriptor map
manipulation library, then this seems to be a very nice-to-have feature.
If you think of traits.js as a trait composition library, then it probably
does introduce too much distraction, especially if the meta-data is not
related to trait composition at all.
One possibility would be to fork traits.js into two libraries, such that the
traits-specific composition library is a specialization of a more
general-purpose property map combinator library. I don't know whether it's
worth doing that. I would need to have a better idea of what other useful
specializations one could construct out of a more general-purpose
library, but perhaps we should have that discussion offline (or at least
fork it off of the traits-oriented discussion thread).
Cheers,
Tom
>
> thx
> kam
>
> ------------------------------
> *From:* Tom Van Cutsem <tomvc at google.com>
> *To:* Kam Kasravi <kamkasravi at yahoo.com>
> *Cc:* es-discuss <es-discuss at mozilla.org>
> *Sent:* Wed, February 17, 2010 6:19:12 PM
> *Subject:* Re: Traits library
>
> As a follow-up to my earlier reply to Kam, I included a diagram at <
> http://code.google.com/p/es-lab/wiki/Traits#API> that helps to clarify
> what kinds of objects and operations are involved in using the library.
>
> On Wed, Feb 17, 2010 at 4:54 PM, Tom Van Cutsem <tomvc at google.com> wrote:
>
>> Hi Kam,
>>
>> One use case when using traits in this way is
>>> whether traits (either using Trait.create or Object.create) could be used
>>> to replace prototypical inheritance rather than
>>> classical inheritance. That is, can traits be used to compose different
>>> blocks from different instances rather than
>>> different classes.
>>>
>>
>> Yes, the traits library enables this, because it allows instances to be
>> 'lifted' into traits. Just like the library provides two ways to generate an
>> object from a property map (either use Object.create or Trait.create), the
>> library provides two ways to generate a property map from an object:
>> - either use the Trait constructor: Trait(object) -> property-map
>> - or use Object.getOwnProperties(object) -> property-map
>>
>> I didn't mention this on the wiki page, but the traits.js library actually
>> goes ahead and adds the "missing" 'getOwnProperties' utility method to
>> Object if it doesn't already exist, precisely because it's so useful in
>> combination with representing traits as property maps. getOwnProperties is a
>> simple utility method based on ES5's getOwnPropertyNames +
>> getOwnPropertyDescriptor built-in methods.
>>
>> Just like Trait.create is the "trait-aware" version of Object.create, the
>> Trait constructor is the "trait-aware" version of Object.getOwnProperties.
>> The Trait constructor will, for example, recognize properties bound to
>> Trait.required, whereas Object.getOwnProperties will not.
>>
>> That said, I envisaged the Trait constructor to be used in the absolute
>> majority of cases in conjunction with an in-line object literal, as in
>> Trait({...}). Generally, I don't think it makes a lot of sense to turn an
>> actual instance back into a trait (it's like turning an object into a
>> class). But the library doesn't stop you from using Trait or
>> Object.getOwnProperties on arbitrary instances if this is really what you
>> want to do.
>>
>> Cheers,
>> Tom
>>
>>
>>>
>>> kam
>>>
>>> ------------------------------
>>> *From:* Tom Van Cutsem <tomvc at google.com>
>>> *To:* Kam Kasravi <kamkasravi at yahoo.com>
>>> *Cc:* es-discuss <es-discuss at mozilla.org>
>>> *Sent:* Wed, February 17, 2010 2:49:43 PM
>>> *Subject:* Re: Traits library
>>>
>>> Hi Kam,
>>>
>>> Thanks for the clarification. As far as I can tell, what you are
>>> describing is an example that would require trait composition to be
>>> postponed until runtime (as it depends on runtime context). The way I see
>>> it, the traits library would not prevent that: since traits are not static
>>> entities but just property maps that are manipulated at runtime, I see no
>>> fundamental obstacle to writing a generic dispatching function that, given
>>> some context, returns the appropriate traits or trait composition making up
>>> a drawing editor.
>>>
>>> However, I would like to point out that if this is your desired use case,
>>> then traits may not be the right building block. As you point out yourself,
>>> the example you're describing seems like a perfect match for multi-methods.
>>> I do not think that 'dynamic trait composition' is a good alternative for
>>> multi-methods. At least, that's not the use case for which traits have been
>>> designed. Traits are an alternative to composition by inheritance. As is the
>>> case in typical single/mixin/multiple-inheritance schemes, the relationship
>>> between the inheriting entities is usually known (and declared) statically
>>> and is immutable. I see traits more like a static building block that can be
>>> used to organize code (while enabling a higher reuse potential than that
>>> provided by classes+single-inheritance).
>>>
>>> Some details:
>>>
>>> It doesn't sound like traits would
>>>> enable this 'pattern' given different methods need to be mixed in with
>>>> appropriate context from the implementation and all methods are final.
>>>>
>>>
>>> Methods are 'final' upon trait composition only when a property map is
>>> instantiated using "Trait.create". If "Object.create" is used, the
>>> instantiated object is a plain Javascript object with all of the
>>> malleability this implies.
>>>
>>>
>>>> Passing attributes like
>>>> background, border in the property descriptor would seem to be an abuse
>>>> of the meta-data framework by passing data not meta-data.
>>>>
>>>
>>> I completely agree. When I proposed the use of attributes to store data
>>> in property descriptors in my earlier message, I thought you meant to store
>>> meta-data.
>>>
>>> Cheers,
>>> Tom
>>>
>>>
>>>>
>>>> thx
>>>> kam
>>>>
>>>> ------------------------------
>>>> *From:* Tom Van Cutsem <tomvc at google.com>
>>>> *To:* Kam Kasravi <kamkasravi at yahoo.com>
>>>> *Cc:* es-discuss <es-discuss at mozilla.org>
>>>> *Sent:* Tue, February 16, 2010 7:18:48 PM
>>>> *Subject:* Re: Traits library
>>>>
>>>> Hi Kam,
>>>>
>>>> If I understand the implementation of traits, it provides a ES5
>>>>> compatible way of composing 'final' properties to an existing object's
>>>>> prototype.
>>>>> Options provide the meta-data required to define the property
>>>>> descriptor such as required, etc. Do traits provide an ability to bind
>>>>> a 'context' to the property in the form of a closure so that the
>>>>> property may be provided with additional information?
>>>>> Effectively a way to curry or export additional information required by
>>>>> the trait when it is called in the context of the object it was added to.
>>>>>
>>>>
>>>> I'm not entirely sure I understand the question. Do you have a
>>>> particular use case in mind or can you give an example to clarify things?
>>>> As far as I can understand, if what you want is additional meta-data
>>>> stored in property descriptors, this can be done by adding additional
>>>> attributes to the descriptors. In effect, that's what the library already
>>>> does for 'required' and 'conflicting' properties.
>>>>
>>>> Cheers,
>>>> Tom
>>>>
>>>>
>>>>>
>>>>> thx
>>>>> kam
>>>>>
>>>>>
>>>>> ------------------------------
>>>>> *From:* Tom Van Cutsem <tomvc at google.com>
>>>>> *To:* es-discuss <es-discuss at mozilla.org>
>>>>> *Sent:* Tue, February 16, 2010 2:55:50 PM
>>>>> *Subject:* Traits library
>>>>>
>>>>> Hi,
>>>>>
>>>>> Mark Miller and I have been working on a small traits library for
>>>>> Javascript. It is documented here: <
>>>>> http://code.google.com/p/es-lab/wiki/Traits>
>>>>>
>>>>> Traits are reusable building blocks for classes, very similar to
>>>>> mixins, but with less gotchas. For example, traits support explicit conflict
>>>>> resolution upon name clashes and the order in which traits are composed is
>>>>> not significant.
>>>>>
>>>>> In a nutshell:
>>>>> - The library is designed for ES5, but backwards-compatible with
>>>>> existing ES3 implementations.
>>>>> - Our library represents traits as ES5 property maps (objects mapping
>>>>> property names to property descriptors). The library exports:
>>>>> - a convenient trait "constructor" to generate property maps from
>>>>> object literals.
>>>>> - a number of "trait combinators" to compose property maps.
>>>>> - a function that can "instantiate" such property maps into objects
>>>>> (analogous to the ES5 Object.create function, but with awareness about
>>>>> trait-specific property semantics).
>>>>>
>>>>> The interesting thing about our choice of transparently representing
>>>>> traits as ES5 property maps is that our library can be used as a
>>>>> general-purpose library for manipulating property descriptors in addition to
>>>>> its use as a library to compose and instantiate traits.
>>>>>
>>>>> A small expository example that uses the library:
>>>>> <
>>>>> http://code.google.com/p/es-lab/source/browse/trunk/src/traits/examples.js
>>>>> >
>>>>>
>>>>> Mark and I were both surprised at how well Javascript accommodates a
>>>>> trait library with very little boilerplate. However, there is one catch to
>>>>> implementing traits as a library. Traits, like classes, are normally simply
>>>>> declared in the program text, but need not necessarily have a runtime
>>>>> representation. Trait composition is normally performed entirely at
>>>>> compile-time (in trait lingo this is called "flattening" the traits). At
>>>>> runtime, no trace of trait composition is left.
>>>>>
>>>>> Because we use a library approach, traits are not declarative entities
>>>>> and must have a runtime representation. Thus, there is a runtime overhead
>>>>> associated with trait creation and composition. Moreover, because the
>>>>> implementation is oblivious to traits, multiple objects instantiated from
>>>>> the same trait "declaration" don't share structure. However, we did design
>>>>> the library such that, if traits are specified using object literals and
>>>>> property renaming depends only on string literals (which is the common
>>>>> case), a partial evaluator could in principle perform all trait composition
>>>>> statically, and replace calls to Trait.create with a specialized
>>>>> implementation that does support structural sharing between instances (just
>>>>> like an implementation that notices multiple calls to Object.create with the
>>>>> same property descriptor map can in principle arrange for the created
>>>>> objects to share structure).
>>>>>
>>>>> Any feedback on our design is welcomed. In particular, it'd be
>>>>> interesting to hear how hard/easy it would be for an implementation to
>>>>> recognize the operations performed by our library in order to perform them
>>>>> statically.
>>>>>
>>>>> Cheers,
>>>>> Tom
>>>>>
>>>>
>>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20100218/3db560d5/attachment-0001.html>
More information about the es-discuss
mailing list