I noted some open issues on "Classes with Trait Composition"

Andreas Rossberg rossberg at google.com
Tue May 24 06:20:33 PDT 2011

On 23 May 2011 19:42, Mark S. Miller <erights at google.com> wrote:
> On Mon, May 23, 2011 at 2:16 PM, Andreas Rossberg <rossberg at google.com>
> wrote:
>> Compare:
>>  class Point {
>>    private x, y
>>    constructor(x0, y0) { x = x0; y = y0 }
>>    public function move(dx, dy) { x += dx; y += dy }
>>    public function abs() { return Math.sqrt(x*x, y*y) }
>>  }
>>  let p = new Point(3, 4)
>>  p.abs()
>> with:
>>  module Point(x0, y0) {
>>    let x = x0, y = y0
>>    export function move(dx, dy) { x += dx; y += dy }
>>    export function abs() { return Math.sqrt(x*x, y*y) }
>>  }
>>  let p = Point(3, 4)  // assuming module functions are reflected into
>> functions
>>  p.abs()
>> Almost the same effect, even though the underlying semantics differs
>> somewhat.
> Regarding the scoping of private instance variables, the version with
> generative module functions is actually much better[1]. In fact, it's the
> same as the objects-as-closures pattern, or the earlier
> <http://wiki.ecmascript.org/doku.php?id=strawman:classes_with_trait_composition&rev=1299750065>
> classes strawman, which is essentially a codification of
> objects-as-closures.

Yes. I didn't want to stress that point, but it may be relevant, too,
for better or worse.

> In the above example, do you anticipate an allocation per method per
> instance? Specifically, does each call to Point allocate a new instance of
> the point module (fine) exporting newly allocated move and abs closures
> (bad). Some codification of objects-as-closures only becomes a viable
> alternative to the current manual class pattern if it can avoid these extra
> allocations.

Well, this was rather an observation than a proposal, so I didn't
anticipate anything specific. But if the language grows in that
direction, people might start using it that way, intended or not,
whether we have classes as well, or not. So it potentially becomes an
issue either way.

> Putting methods on a shared prototype essentially treats the prototype as a
> vtable. This implementation path is messy, but is well trodden in current JS
> implementations. Avoiding extra allocations for objects-as-closures, whether
> sugared by your generative module pattern on my earlier classes strawman,
> would seem to require a new vtable mechanism not directly mapped onto
> prototype inheritance. Perhaps the "hidden classes" optimization already
> provides a context in which we can reuse implementation machinery between
> these two vtable-like mechanisms?

I'm afraid I don't know the "hidden classes" optimization. But
speculating a bit, one implementation technique I could envision is
the following. It amounts to moving the closure environment from
individual functions to the module instance object:

- Add the module's (internal) lexical environment as a hidden property
Env to the module instance object.
- Store (direct) function members as mere code objects, not closures.
- Treat projection from a module M (which we can distinguish
statically) specially. If we project a yet unclosed function:
  * if it's called right away, pass M.Env as the environment,
  * if it's not called, allocate a proper closure for it with environment M.Env,

Allocating the individual closure is effectively deferred to the rarer
case where we extract a function without calling it immediately. This
technique would only apply to functions that are direct members of the
module, but that's usually the vast majority. For others, you'd close
immediately, as you'd do now.

Note that this is merely an implementation trick, nothing the spec
would or should have to worry about.


  module M {
    let x = 2  // goes into M.Env
    export function f() { return x }

  let f = M.f  // M is a module (statically), f a function
(dynamically), so close over M.Env
  f()  // 2

> The May meeting is the close of the "additive phase" of designing ES-next.
> Following that, we hope for some consolidation and subtraction, among other
> activities (prototype implementations, web testing, spec writing,
> etc). Modules are already in. If classes get accepted in May, then I would
> consider it in bounds after May to grow modules slightly in order to remove
> classes completely. This would seem to be an excellent tradeoff. As I
> recall, you were planning to be at the July meeting? I think this would be a
> good focus topic for July.

OK, I will try to think this through in a bit more detail until then.


More information about the es-discuss mailing list