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

classic Classic list List threaded Threaded
78 messages Options
1234
Reply | Threaded
Open this post in threaded view
|

Re: Modules first or second class (Re: I noted some open issues on "Classes with Trait Composition")

Dave Herman
> Just a note on this: for me, that means Harmony modules
> are a step back from what I can implement in JS/now.

How is it a step back, if you can already implement it? We're not taking objects away from JavaScript.

> Not
> having first-class modules has been a major drawback in
> Haskell (which has a strictly 1980s-style module system),
> leading to all kinds of work-arounds.

Usually when people deride the Haskell module system, they are comparing it to the ML module system, which... is also a second-class module system.

> One of these workarounds, which I expect to see and use
> a lot in Harmony, is to have first-class modules-as-records
> (or objects) inside second-class built-in-modules.
>
> Is this an intended outcome of the Harmony module design?

That's kind of a loaded question, given the word "workaround" but yes, it's definitely an intended outcome of the design to have second-class modules. Modules that are second-class have many benefits over first-class modules:

- they are extremely lightweight, which is really important for ergonomics

- they make it possible to do compile-time linking and variable resolution

- they can share static information, such as sets of bindings (not that import * would not work with first-class modules), macros, or types (both of which are, IMO, worth considering in the future for ECMAScript)

Moreover, loaders make it possible to do dynamic linking. It's just a little harder than in e.g. SML. I say that's the right trade-off: writing simple modules is trivial, and writing modules with pluggable dependencies is still possible.

Dave

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Modules first or second class (Re: I noted some open issues on "Classes with Trait Composition")

Dave Herman
> - they can share static information, such as sets of bindings (not that import * would not work with first-class modules)...

Oops, meant to say: "note that import * would not work"

Dave

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Modules first or second class (Re: I noted some open issues on "Classes with Trait Composition")

Claus Reinke
In reply to this post by Dave Herman
> I think "modules are a construct that evaluates to an object"
> is the wrong way to think about them. Syntactic modules
> are a second-class construct that is not an expression. You
> can reflect on modules at runtime, and that reflection is
> provided as an object, but that's because almost all
> compound data structures in JS are objects. But I would
> advise against describing modules as a kind of object.

>> Just a note on this: for me, that means Harmony modules
>> are a step back from what I can implement in JS/now.
>
> How is it a step back, if you can already implement it? We're
> not taking objects away from JavaScript.

If I implement a module loader[1] in JS/now, my modules
are first-class functions from export objects to export object.
Normally, that is just used to model import dependencies,
but fully instantiated modules are (export) objects, and
first-class modules fit right into the pattern.

You're advising that thinking about Harmony modules
as first-class objects is not the best way to think about them.

Yes, I can continue to use first-class modules inside Harmony
modules, but that makes two separate concepts where there
used to be one.

>> Not
>> having first-class modules has been a major drawback in
>> Haskell (which has a strictly 1980s-style module system),
>> leading to all kinds of work-arounds.
>
> Usually when people deride the Haskell module system,
> they are comparing it to the ML module system, which...
> is also a second-class module system.

A hobby horse of mine [2, especially chapter 4 and sections
8.2/8.3]:-)

The proponents of Haskell's module system were explicitly
looking for something simple (just namespacing), so it is
not so much deriding as knowing that there are better
solutions. I added a first-class module system to a dynamically
typed functional language back in the 1990s, and from the
literature then, it seemed that some ML implementations
already had first-class modules (some had only higher-order
functors, first-class in the separate module language).

Naturally, since I spent a lot of time thinking about the
advantages of first-class modules, it is great to be able
to implement them, including loaders, so easily in
Javascript;-)

Modulo loaders, they are also easy in Haskell (I worked
in Mark Jones' group for a while - he did some nice work
in that area), but since most of the infrastructure is geared
towards the second-class modules, first-class modules
aren't used as much as their advantages would suggest.

>> One of these workarounds, which I expect to see and
>> use a lot in Harmony, is to have first-class modules-
>> as-records (or objects) inside second-class built-in-
>> modules.
>>
>> Is this an intended outcome of the Harmony module design?
>
> That's kind of a loaded question, given the word "workaround"

No loading intended. I realize that the majority view might
not yet call for first-class modules, might therefore find them
counter-intuitive. Those developers might think of first-class
modules as an abstract complication, rather than a simplifying
and practical tool. It is just those who have grown used to their
advantages who need workarounds in second-class modules.

> but yes, it's definitely an intended outcome of the design to
> have second-class modules. Modules that are second-class
> have many benefits over first-class modules:
>
> - they are extremely lightweight, which is really important for ergonomics

I find modules-as-objects/records lightweight, but given the
discussions I've seen on the CommonJS list regarding module
formats, you're probably right for the majority of users.

> - they make it possible to do compile-time linking and variable resolution

For Javascript and other dynamic languages, compile-time
for one piece of code is often runtime for its host code.
Having a phase separation, after which all variables are
resolved, is great but is that not addressed by destructuring?

> - they can share static information, such as sets of bindings
> (note that import * would not work with first-class modules),
> macros, or types (both of which are, IMO, worth considering
> in the future for ECMAScript)

Import * is useful, but isn't it based on the fixed shape
of the module we import from? In a typed language, if there
is a static type that includes the property names of an object,
import * from that object becomes possible. And, in Javascript,
wouldn't a restricted 'with', working only on frozen objects,
serve the same purpose?

Btw, can I do 'import *' on a dynamically loaded module?

Types and modules are tricky, because of the various design
options (some of which are mentioned in section 8.2 of [2]).

> Moreover, loaders make it possible to do dynamic linking.
> It's just a little harder than in e.g. SML. I say that's the right
> trade-off: writing simple modules is trivial, and writing
> modules with pluggable dependencies is still possible.

And reflection represents module instances as objects. I
was just surprised that you insisted on the second-class
view as central (rather than it being a simplified view on
first-class modules).

Thanks for the clarification,
Claus

[1]
http://libraryinstitute.wordpress.com/2010/12/01/loading-javascript-modules/
[2] Functions, Frames, and Interactions - completing a
    lambda-calculus-based purely functional language with
    respect to programming-in-the-large and interactions
    with runtime environments, Claus Reinke, 1998
    http://community.haskell.org/~claus/publications/phd.html

 

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Andreas Rossberg-4
In reply to this post by Dave Herman
On 20 May 2011 18:00, David Herman <[hidden email]> wrote:
> I think "modules are a construct that evaluates to an object" is the wrong way to think about them. Syntactic modules are a second-class construct that is not an expression. You can reflect on modules at runtime, and that reflection is provided as an object, but that's because almost all compound data structures in JS are objects. But I would advise against describing modules as a kind of object.
>
> And I think an important aspect of classes is that they are providing a declarative convenience for doing things that people *already* do with objects in JS today.

I see what you are saying, and yes, they are intended to serve a
different purpose. But they still share a lot of semantic overlap. And
I foresee that the overlap will increase overtime, as the language
evolves.

Take just one specific example: there already is the proposal for
extending modules with "module functions"
(http://wiki.ecmascript.org/doku.php?id=strawman:simple_module_functions)
-- which makes a lot of sense, is straightforward, and I'm sure that
people will demand something along these lines sooner or later. But
for better or worse, modules now actually have become classes!
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. You can even express simple inheritance with import and
export, depending on how general they will be in the end.

Obviously, there are aspects that you still cannot express with
modules but can with classes, and vice versa. But my point is that at
their core, they end up being pretty similar things. And their
differences might eventually start looking rather accidental. I would
feel better if we thought a bit harder about ways to utilize the
commonalities before we grow the size of the language too quickly.

/Andreas
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Andreas Rossberg-4
In reply to this post by Mark S. Miller-2
On 20 May 2011 15:42, Mark S. Miller <[hidden email]> wrote:
> Modules aren't generative.

If you mean that you cannot create several objects from them, then
yes, but see my reply to Dave.

However, I was primarily wondering about static members, which don't
provide any generativity in that sense either.

/Andreas


> On May 20, 2011 7:58 AM, "Andreas Rossberg" <[hidden email]> wrote:
>> On 19 May 2011 16:05, David Herman <[hidden email]> wrote:
>>> Yes, we've talked about this. One of the issues I don't know how to
>>> resolve is if we want to allow the specification of class properties aka
>>> statics, then those need *not* to be in the scope of the constructor
>>> arguments, which ends up with very strange scoping behavior:
>>>
>>>    var x = "outer"
>>>    class C(x) {
>>>        static foo = x // "outer" -- whoa!
>>>    }
>>>
>>> I'm not 100% up on the current thinking of the group that's been working
>>> on classes, and whether they are including statics in the design, but I
>>> think they are.
>>
>> Oh, it wasn't clear to me that we really want to have static members.
>> I may be biased here, but I always viewed static members as just a
>> poor man's substitute for a proper module system. Fortunately, it
>> looks like we will have a real one instead!
>>
>> To be honest, I'm a bit worried that there will be a _lot_ of semantic
>> redundancy in the end. After adding modules + classes + static members
>> (+ traits?), there would be at least three or four different,
>> complicated constructs that evaluate to some kind of object, with
>> significant functional overlap.
>>
>> Thanks,
>> /Andreas
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Mark S. Miller-2
In reply to this post by Andreas Rossberg-4
On Mon, May 23, 2011 at 2:16 PM, Andreas Rossberg <[hidden email]> wrote:
On 20 May 2011 18:00, David Herman <[hidden email]> wrote:
> I think "modules are a construct that evaluates to an object" is the wrong way to think about them. Syntactic modules are a second-class construct that is not an expression. You can reflect on modules at runtime, and that reflection is provided as an object, but that's because almost all compound data structures in JS are objects. But I would advise against describing modules as a kind of object.
>
> And I think an important aspect of classes is that they are providing a declarative convenience for doing things that people *already* do with objects in JS today.

I see what you are saying, and yes, they are intended to serve a
different purpose. But they still share a lot of semantic overlap. And
I foresee that the overlap will increase overtime, as the language
evolves.

Take just one specific example: there already is the proposal for
extending modules with "module functions"
(http://wiki.ecmascript.org/doku.php?id=strawman:simple_module_functions)
-- which makes a lot of sense, is straightforward, and I'm sure that
people will demand something along these lines sooner or later. But
for better or worse, modules now actually have become classes!
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. Personally, I still like that earlier strawman better. But I gave up on it based on the difficulty of convincing implementors to implement it efficiently. Your's seems to have the same efficiency issue. Since you are now involved in JS implementation, let me ask regarding your efforts:

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. 

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?

[1] The semantics of the "x" reference in your move and abs methods differs so violently from a lexical variable reference <https://mail.mozilla.org/pipermail/es-discuss/2011-May/014516.html> that we must not make it appear to be a lexical variable reference. Starting with ES5, we have finally rescued lexical scoping from JavaScript's messy past. Let's not lose the ground we gained. Brevity is important, but scoping clarity is way more important than brevity.

 
You can even express simple inheritance with import and
export, depending on how general they will be in the end.

Obviously, there are aspects that you still cannot express with
modules but can with classes, and vice versa. But my point is that at
their core, they end up being pretty similar things. And their
differences might eventually start looking rather accidental. I would
feel better if we thought a bit harder about ways to utilize the
commonalities before we grow the size of the language too quickly.

Today is the day before the May meeting. If generative module functions could be grown to meet the needs of classes, I think I would prefer the outcome as compared to the current classes strawman. However, the open issues that would need to be explored to determine this vastly exceeds the time between now and then.

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.
 

/Andreas



--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Mark S. Miller-2
In reply to this post by Andreas Rossberg-4


On Mon, May 23, 2011 at 7:22 AM, Andreas Rossberg <[hidden email]> wrote:
On 20 May 2011 15:42, Mark S. Miller <[hidden email]> wrote:
> Modules aren't generative.

If you mean that you cannot create several objects from them, then
yes, but see my reply to Dave.

However, I was primarily wondering about static members, which don't
provide any generativity in that sense either.

Static members on classes are generative merely because classes are generative:

    function makeFoo() {
      return class Foo {
        static x = Math.random();
        //...
      }
    }

Your reply to Dave makes use of generative module functions. Yes, if we have generative module functions then my objection disappears. Modules would then also be generative.


 

/Andreas


> On May 20, 2011 7:58 AM, "Andreas Rossberg" <[hidden email]> wrote:
>> On 19 May 2011 16:05, David Herman <[hidden email]> wrote:
>>> Yes, we've talked about this. One of the issues I don't know how to
>>> resolve is if we want to allow the specification of class properties aka
>>> statics, then those need *not* to be in the scope of the constructor
>>> arguments, which ends up with very strange scoping behavior:
>>>
>>>    var x = "outer"
>>>    class C(x) {
>>>        static foo = x // "outer" -- whoa!
>>>    }
>>>
>>> I'm not 100% up on the current thinking of the group that's been working
>>> on classes, and whether they are including statics in the design, but I
>>> think they are.
>>
>> Oh, it wasn't clear to me that we really want to have static members.
>> I may be biased here, but I always viewed static members as just a
>> poor man's substitute for a proper module system. Fortunately, it
>> looks like we will have a real one instead!
>>
>> To be honest, I'm a bit worried that there will be a _lot_ of semantic
>> redundancy in the end. After adding modules + classes + static members
>> (+ traits?), there would be at least three or four different,
>> complicated constructs that evaluate to some kind of object, with
>> significant functional overlap.
>>
>> Thanks,
>> /Andreas
>



--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Mark S. Miller-2
In reply to this post by Mark S. Miller-2
On Mon, May 23, 2011 at 10:42 AM, Mark S. Miller <[hidden email]> wrote:
On Mon, May 23, 2011 at 2:16 PM, Andreas Rossberg <[hidden email]> wrote:
On 20 May 2011 18:00, David Herman <[hidden email]> wrote:
> I think "modules are a construct that evaluates to an object" is the wrong way to think about them. Syntactic modules are a second-class construct that is not an expression. You can reflect on modules at runtime, and that reflection is provided as an object, but that's because almost all compound data structures in JS are objects. But I would advise against describing modules as a kind of object.
>
> And I think an important aspect of classes is that they are providing a declarative convenience for doing things that people *already* do with objects in JS today.

I see what you are saying, and yes, they are intended to serve a
different purpose. But they still share a lot of semantic overlap. And
I foresee that the overlap will increase overtime, as the language
evolves.

Take just one specific example: there already is the proposal for
extending modules with "module functions"
(http://wiki.ecmascript.org/doku.php?id=strawman:simple_module_functions)
-- which makes a lot of sense, is straightforward, and I'm sure that
people will demand something along these lines sooner or later. But
for better or worse, modules now actually have become classes!
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. Personally, I still like that earlier strawman better. But I gave up on it based on the difficulty of convincing implementors to implement it efficiently. Your's seems to have the same efficiency issue. Since you are now involved in JS implementation, let me ask regarding your efforts:

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. 

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,

Should be

... your generative module pattern *or* 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?

[1] The semantics of the "x" reference in your move and abs methods differs so violently from a lexical variable reference <https://mail.mozilla.org/pipermail/es-discuss/2011-May/014516.html> that we must not make it appear to be a lexical variable reference. Starting with ES5, we have finally rescued lexical scoping from JavaScript's messy past. Let's not lose the ground we gained. Brevity is important, but scoping clarity is way more important than brevity.

 
You can even express simple inheritance with import and
export, depending on how general they will be in the end.

Obviously, there are aspects that you still cannot express with
modules but can with classes, and vice versa. But my point is that at
their core, they end up being pretty similar things. And their
differences might eventually start looking rather accidental. I would
feel better if we thought a bit harder about ways to utilize the
commonalities before we grow the size of the language too quickly.

Today is the day before the May meeting. If generative module functions could be grown to meet the needs of classes, I think I would prefer the outcome as compared to the current classes strawman. However, the open issues that would need to be explored to determine this vastly exceeds the time between now and then.

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.
 

/Andreas



--
    Cheers,
    --MarkM



--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Brendan Eich-3
In reply to this post by Mark S. Miller-2
On May 23, 2011, at 10:48 AM, Mark S. Miller wrote:

> Static members on classes are generative merely because classes are generative:
>
>     function makeFoo() {
>       return class Foo {
>         static x = Math.random();
>         //...
>       }
>     }
>
> Your reply to Dave makes use of generative module functions. Yes, if we have generative module functions then my objection disappears. Modules would then also be generative.

Not without the module-function head syntax, or we lose lexical scope with static errors for typos, though. The last issue is huge, and it does not affect only import M.*.

Possibly we have different undrestandings of module functions, but the base module system is static and second class. This should be unchanged by any extension, and extensions building on module system should not have "too different" semantics (I'm a broken record on this; also I agree it bites generators, wherefore the function*(){} minimal generator syntax idea. The syntax difference need not be huge,but it should be distinctive).

/be

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Andreas Rossberg-4
In reply to this post by Mark S. Miller-2
On 23 May 2011 19:42, Mark S. Miller <[hidden email]> wrote:

> On Mon, May 23, 2011 at 2:16 PM, Andreas Rossberg <[hidden email]>
> 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.

Example:

  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.

Thanks,
/Andreas
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Andreas Rossberg-4
In reply to this post by Mark S. Miller-2
On 23 May 2011 19:48, Mark S. Miller <[hidden email]> wrote:

> On Mon, May 23, 2011 at 7:22 AM, Andreas Rossberg <[hidden email]>
> wrote:
>> On 20 May 2011 15:42, Mark S. Miller <[hidden email]> wrote:
>> > Modules aren't generative.
>>
>> If you mean that you cannot create several objects from them, then
>> yes, but see my reply to Dave.
>>
>> However, I was primarily wondering about static members, which don't
>> provide any generativity in that sense either.
>
> Static members on classes are generative merely because classes are
> generative:
>     function makeFoo() {
>       return class Foo {
>         static x = Math.random();
>         //...
>       }
>     }

OK, now I see what you mean. However, I'd say that is not really a
difference between the semantics of modules vs static class members
per se, but simply a consequence of classes being first-class, while
modules are restricted to second-class status. That, in turn, is
merely a (well-advised) design choice of the current proposals, but
nothing inherent to either modules or classes.

/Andreas
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Brendan Eich-3
In reply to this post by Andreas Rossberg-4
On May 24, 2011, at 6:20 AM, Andreas Rossberg wrote:

> - 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,

This is already done by SpiderMonkey and I believe other engines, with function expressions in certain contexts.

Not to rain on the module function parade (I'm leaning away from classes, in search of simpler solutions that compose well, so I have a soft spot for it), but reifying the module as an object with its exports as properties means those properties are non-configurable and non-writable. That goes against the classes-as-sugar-for-prototypal-objects goal. The -prototypal part is missing too.

/be

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Gavin Barraclough
In reply to this post by Brendan Eich-3
Brendan,

Out of interest was a C++/Java style constructor considered, with the constructor name matching the class name?

cheers,
Gavin.


On May 16, 2011, at 8:02 AM, Brendan Eich wrote:

On May 16, 2011, at 4:54 AM, Dmitry A. Soshnikov wrote:

On 16.05.2011 10:49, Brendan Eich wrote:
On May 15, 2011, at 10:01 PM, Brendan Eich wrote:

http://wiki.ecmascript.org/doku.php?id=strawman:classes_with_trait_composition#open_issues

This looks pretty good at a glance, but it's a lot, and it's new.

Looking closer, I have to say something non-nit-picky that looks bad and smells like committee:


Two kinds of inheritance, depending on the dynamic type of the result of evaluating the //MemberExpression// on the right of ''extends''? That will be confusing.

Is the traits-composition way really needed in this proposal? If so, then please consider not abuse ''extends'' to mean ''compose'' depending on dynamic type of result of expression to its right.


Some simple examples of all use-cases would are needed I think.

Regarding `new` keyword for the constructor (aka initializer), after all, it als may be OK. E.g. Ruby uses `new` as exactly the method of a class -- Array.new, Object.new, etc. Though,  `constructor` is also good yeah.

My point is not to bikeshed, rather (a) to name existing prototype properties minimally, (b) to avoid preempting other names.

Good, bad, or in between, the prototypal pattern in JS for constructor C binds C.prototype.constructorr to C. It does not bind C.prototype.new.


Regarding two inheritance types, I think better to make nevertheless one inheritance type -- linear (by prototype chain). And to make additionally small reusable code units -- mixins or traits -- no matter. Thus, of course if they will also be delegation-based and not just copy-own-properties, then we automatically get a sort of multiple inheritance.

Self has multiple prototypes and you can use them for all kinds of inheritance patterns.




Delegation-based mixins though can be implemented as a library using proxies (example: https://github.com/DmitrySoshnikov/es-laboratory/blob/master/examples/mixin.js, implementation: https://github.com/DmitrySoshnikov/es-laboratory/blob/master/src/mixin.js, notice I also used Object.new :)).

Proxies are too costly, though. They always have a handler full of traps. The idea with classes is to capture prototypal inheritance as used today. The idea with traits is to make composition flexible, with fast failure on conflict and tools to rename around conflicts.

Putting classes and traitts together should be doable but it shouldn't use the same sytnax (extends) and it shouldn't require proxies.

/be
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Bob Nystrom
It was. The main problem that comes to mind is that it doesn't work with anonymous classes. Even with named classes, I find it can be tedious and repetitive, especially with long class names.

Javascript's current class-as-constructor syntax is nicely terse and doesn't require stuttering the "class" name. I think the goal with the class proposal was to aim for that level of syntactic lightness.

- bob

On Tue, Jun 7, 2011 at 12:42 PM, Gavin Barraclough <[hidden email]> wrote:
Brendan,

Out of interest was a C++/Java style constructor considered, with the constructor name matching the class name?

cheers,
Gavin.


On May 16, 2011, at 8:02 AM, Brendan Eich wrote:

On May 16, 2011, at 4:54 AM, Dmitry A. Soshnikov wrote:

On 16.05.2011 10:49, Brendan Eich wrote:
On May 15, 2011, at 10:01 PM, Brendan Eich wrote:

http://wiki.ecmascript.org/doku.php?id=strawman:classes_with_trait_composition#open_issues

This looks pretty good at a glance, but it's a lot, and it's new.

Looking closer, I have to say something non-nit-picky that looks bad and smells like committee:


Two kinds of inheritance, depending on the dynamic type of the result of evaluating the //MemberExpression// on the right of ''extends''? That will be confusing.

Is the traits-composition way really needed in this proposal? If so, then please consider not abuse ''extends'' to mean ''compose'' depending on dynamic type of result of expression to its right.


Some simple examples of all use-cases would are needed I think.

Regarding `new` keyword for the constructor (aka initializer), after all, it als may be OK. E.g. Ruby uses `new` as exactly the method of a class -- Array.new, Object.new, etc. Though,  `constructor` is also good yeah.

My point is not to bikeshed, rather (a) to name existing prototype properties minimally, (b) to avoid preempting other names.

Good, bad, or in between, the prototypal pattern in JS for constructor C binds C.prototype.constructorr to C. It does not bind C.prototype.new.


Regarding two inheritance types, I think better to make nevertheless one inheritance type -- linear (by prototype chain). And to make additionally small reusable code units -- mixins or traits -- no matter. Thus, of course if they will also be delegation-based and not just copy-own-properties, then we automatically get a sort of multiple inheritance.

Self has multiple prototypes and you can use them for all kinds of inheritance patterns.




Delegation-based mixins though can be implemented as a library using proxies (example: https://github.com/DmitrySoshnikov/es-laboratory/blob/master/examples/mixin.js, implementation: https://github.com/DmitrySoshnikov/es-laboratory/blob/master/src/mixin.js, notice I also used Object.new :)).

Proxies are too costly, though. They always have a handler full of traps. The idea with classes is to capture prototypal inheritance as used today. The idea with traits is to make composition flexible, with fast failure on conflict and tools to rename around conflicts.

Putting classes and traitts together should be doable but it shouldn't use the same sytnax (extends) and it shouldn't require proxies.

/be
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Brendan Eich-3
In reply to this post by Gavin Barraclough
On Jun 7, 2011, at 12:42 PM, Gavin Barraclough wrote:

Brendan,

Out of interest was a C++/Java style constructor considered, with the constructor name matching the class name?

I'm not sure -- I wasn't in on the earlier design sessions among the champions. I know "new" was used, but if we are sugaring prototypal inheritance, we need something to create "constructor" in the prototype (which is where method definitions written directly in the class body bind their names).

Having some backstage magic wire up "constructor" is possible but then you have two names for the constructor. That is a wart.

The bigger issue is that doing this preempts use of "new" as a prototype property name (allowed by ES5).

So to keep things simple, express the prototypal machinery already in the language directly and explicitly, and avoid preempting "new", we've settled on "constructor".

The bigger issues with classes to close down include private instance variable syntax and semantics, and static method s&s. Some followup work is already under way here. We need to get this solid by the July TC39 meeting.

/be


cheers,
Gavin.


On May 16, 2011, at 8:02 AM, Brendan Eich wrote:

On May 16, 2011, at 4:54 AM, Dmitry A. Soshnikov wrote:

On 16.05.2011 10:49, Brendan Eich wrote:
On May 15, 2011, at 10:01 PM, Brendan Eich wrote:

http://wiki.ecmascript.org/doku.php?id=strawman:classes_with_trait_composition#open_issues

This looks pretty good at a glance, but it's a lot, and it's new.

Looking closer, I have to say something non-nit-picky that looks bad and smells like committee:


Two kinds of inheritance, depending on the dynamic type of the result of evaluating the //MemberExpression// on the right of ''extends''? That will be confusing.

Is the traits-composition way really needed in this proposal? If so, then please consider not abuse ''extends'' to mean ''compose'' depending on dynamic type of result of expression to its right.


Some simple examples of all use-cases would are needed I think.

Regarding `new` keyword for the constructor (aka initializer), after all, it als may be OK. E.g. Ruby uses `new` as exactly the method of a class -- Array.new, Object.new, etc. Though,  `constructor` is also good yeah.

My point is not to bikeshed, rather (a) to name existing prototype properties minimally, (b) to avoid preempting other names.

Good, bad, or in between, the prototypal pattern in JS for constructor C binds C.prototype.constructorr to C. It does not bind C.prototype.new.


Regarding two inheritance types, I think better to make nevertheless one inheritance type -- linear (by prototype chain). And to make additionally small reusable code units -- mixins or traits -- no matter. Thus, of course if they will also be delegation-based and not just copy-own-properties, then we automatically get a sort of multiple inheritance.

Self has multiple prototypes and you can use them for all kinds of inheritance patterns.




Delegation-based mixins though can be implemented as a library using proxies (example: https://github.com/DmitrySoshnikov/es-laboratory/blob/master/examples/mixin.js, implementation: https://github.com/DmitrySoshnikov/es-laboratory/blob/master/src/mixin.js, notice I also used Object.new :)).

Proxies are too costly, though. They always have a handler full of traps. The idea with classes is to capture prototypal inheritance as used today. The idea with traits is to make composition flexible, with fast failure on conflict and tools to rename around conflicts.

Putting classes and traitts together should be doable but it shouldn't use the same sytnax (extends) and it shouldn't require proxies.

/be
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Gavin Barraclough
Cheers Brendan.  I must say, I really like how the class sugar is coming together.  It seems that more closely matching a familiar syntax might make things a little more approachable for existing OO programmers, but I certainly see the elegance in using "constructor" directly.

thanks,
G.


On Jun 7, 2011, at 12:57 PM, Brendan Eich wrote:

> I'm not sure -- I wasn't in on the earlier design sessions among the champions. I know "new" was used, but if we are sugaring prototypal inheritance, we need something to create "constructor" in the prototype (which is where method definitions written directly in the class body bind their names).
>
> Having some backstage magic wire up "constructor" is possible but then you have two names for the constructor. That is a wart.
>
> The bigger issue is that doing this preempts use of "new" as a prototype property name (allowed by ES5).
>
> So to keep things simple, express the prototypal machinery already in the language directly and explicitly, and avoid preempting "new", we've settled on "constructor".
>
> The bigger issues with classes to close down include private instance variable syntax and semantics, and static method s&s. Some followup work is already under way here. We need to get this solid by the July TC39 meeting.
>
> /be

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Gavin Barraclough
In reply to this post by Bob Nystrom
On Jun 7, 2011, at 12:57 PM, Bob Nystrom wrote:

> The main problem that comes to mind is that it doesn't work with anonymous classes.

Ah, good point, I hadn't considered anonymous classes.  Clearly we could solve this with a solution specific to these cases (say, "class(){ /*...*/ }" for anonymous class constructors?), but having mismatching syntax in these cases would be a little unfortunate.

thanks,
G.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

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

Bob Nystrom
On Tue, Jun 7, 2011 at 1:19 PM, Gavin Barraclough <[hidden email]> wrote:
Ah, good point, I hadn't considered anonymous classes.  Clearly we could solve this with a solution specific to these cases (say, "class(){ /*...*/ }" for anonymous class constructors?), but having mismatching syntax in these cases would be a little unfortunate.

That might work, but has the same problem as "new" I believe, where "class" is a valid property name. It also might be a bit confusing if we later add support for nested classes.

For what it's worth, I find "constructor" painfully long, but it seems to be the best solution. I definitely prefer using a single standard token instead of the class name. I hate having to type the same thing twice, especially if I'm writing a class WithSomePainfullyLongNameWhichSadlyDoesOccurInPractice.

Just for kicks, here's an even more radical idea: no name at all:

class Monkey {
  () {
    log("I am the monkey's constructor.");
  }
}

class Point {
  (x, y) { this.x = x; this.y = y; }
}

It's delightfully terse, but also completely foreign and non-obvious. I'm 90% certain this is a terrible idea.

- bob

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
1234