Tom Van Cutsem
tomvc at google.com
Tue Feb 16 14:55:50 PST 2010
Mark Miller and I have been working on a small traits library for
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
In a nutshell:
- The library is designed for ES5, but backwards-compatible with existing
- 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
- 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:
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.
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the es-discuss