Traits library

Tom Van Cutsem tomvc at google.com
Wed Feb 17 18:19:12 PST 2010


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/20100217/cd0fa0b8/attachment.html>


More information about the es-discuss mailing list