Re: Good-bye constructor functions?

2013-01-09 Thread Herby Vojčík

Sorry if I was too dense in my reply so things weren't understood. I
don't know how to reply put things efficiently because without big
picture, isolated cherry-picks seem ridiculous and properly put big
picture is often tl;dr-ed.

Concrete replies below.

Allen Wirfs-Brock wrote:

On Jan 8, 2013, at 12:45 AM, Herby Vojčík wrote:



Allen Wirfs-Brock wrote:

On Jan 7, 2013, at 4:09 PM, Herby Vojčík wrote:


...

I just don't see such an inconsistency in the current ES6 spec.
draft. A constructor is just a function that is usually called
with a this value. This is true whether it is called by the
[[Constructor]] internal method or via a super/super.constructor
call. In either case, the primary purpose of the constructor is
to perform initialization actions upon the this value. Where is
the inconsistency?

(I claim that) in any circumstances, what developers want to
express when writing `super(...args)` in the constructoro of
SubFoo, is: On my this, which is now instance of SubFoo, I want
the identical initialization code to be run, which `new
Foo(...args)` would run to initialize newly created instance of
Foo

That's not true. Because the spec is trying to serve two masters:
F and F.prototype.constructor. It is impossible.

The fixed semantics of [[Construct]] for `class` ((1) above)  is
fixing this by only serving one master: F.prototype.constructor
(in line 3).


I agree with your above statement about initialization.  But I also
content that is exactly what the current specification of super does
within a constructor function (subject, of course to what the
invoked methods actually are coded to do).  What I don't see  is why
you


What's it? super does call the .prototype.constructor of superclass,
yes, I know that well, ...

think otherwise.  I need a clearer concrete explanation of what you
see is the problem, prefably without a forward reference to what you
think is the solution.

...but new does not call the .prototype.constructor.

There this does not hold for `super(...args)` behaviour:
On my this, which is now instance of SubFoo, I want the identical
initialization code to be run, which `new Foo(...args)` would run to
initialize newly created instance of Foo.

And if you argue they are identical at the beginning, I say they can be
desynchronized, they will, and it does not matter how is the default case.

This state of serving two masters (new F, super F.prototype.constructor)
is a design issue / inconsistency / bug in the core of the language.

And sorry if I mention the aolution (it is simply call
.prototype.constructor in new for `class`), but it saves the model of
super-without-special-cases for constructor, which is fine (special
cases aren't).


The only anomaly I see is that a handful of legacy built-ins do
completely different things for new operator originated calls in
 contrast to regular function calls. There is no confusion in
the spec. about this and the mechanism for accomplishing it.
However such split behavior can't be declaratively defined in a
normal function or class declaration. In the other thread at
https://mail.mozilla.org/pipermail/es-discuss/2013-January/027864.html



I described how this split behavior an be procedurally described

in such declarations and also described how the same technique
can be applied to the offending built-in constructors (r any
user defined class constructor) to discriminate between
initialization and called behavior, even when called via
super.

Yes, but it is a workaround.


Or, alternatively stated, it shows how the objective can be met
without any further complicating the actual language.   That is
arguably a good thing, not just a woprkaround


Taken ad absurdum, JS is turing complete, you can achieve anything
without complicating the actual language.


The only fix I saw that you made to super was that in you
sketch constructor methods defined via a class definition are
only used for instance initialization, so there doesn't need to
be any code to determine between initialization and call
behavior. Constructor behavior is always initialization
behavior.

Yes, it is there. As a free bonus, btw. The main druver for the
design was new/super two masters fixing. Then, later (Brendan Eich
will not like this ;-) ) the beauty of breaking the tight coupling
and not needing [[Call]] at all for object with [[Construct]].

There are in fact TWO freebies: - [[Call]] separated from
[[Construct]] - you get default constructor for free; by not
defining it explicitly.


Sorry, I still don't see it, you have to explain both the problem
and your solution more concretely.


You probably see [[Call]] / [[Construct]] separation - class object's
[[Call]] is orthogonal to what [[Construct]] does, since it is specified
to call .prototype.constructor. It follows naturally from the fact that
class !== constructor.

So the issue needing explanation is free default constructor, I
presume (tell me if I am wrong).

It goes this way: if the [[Construct]] has proposed 

Re: Good-bye constructor functions?

2013-01-08 Thread Herby Vojčík



Allen Wirfs-Brock wrote:


On Jan 7, 2013, at 4:09 PM, Herby Vojčík wrote:




Allen Wirfs-Brock wrote:

OK, I ready you proposal. I'll summaries it:

class Sub extends Super {
constructor (...args) {
super(...args); //or super.constructor(...args) because they mean the
same thing.
}
}

creates an (almost) ordinary object that is the initial value of the
Sub binding. The [[Prototype]] of Sub is the value of Super. Sub is
created with a prototype property whose value is a new ordinary
object whose [[Prototype]] values is Super.prototype. Sub.prototype
has a method property named constructor whose value is a super
bound method function with the user specified body. There is nothing
special about this method, it it just like any other method defined
in a class declaration. In particular it does not have a
[[Construct]] internal property.

The only thing exotic about Sub is that the object has a
[[Construct]] internal method. It does not have a [[Call]] internal
method. The definition of its [[Construct]] in almost JS pseudo code is:



(1):

//internal method this.[[Constructor]](argList):
let newObj = this.@@create(); //eg Sub.@@create();
let replacementObj = this.prototype.constructor.apply(newObj, argList);
if (typeof replacementObj == object replacementObj !== null)
return replacementObj
return newObj;

(end of (1))


Implications:
Sub === Sub.prototype.constructor evaluates to false.
To create a new instance of Sub say:
new Sub()
The following is a TypeError, because Sub does not have a [[Call]]
internal method:
Sub()
The following is a TypeError, because Sub.prototype.constructor does
not have a [[Construct]] internal method:
new Sub.prototype.constructor()
Sub.prototype.constructor can be called directly or as a method
invocation including via a super call a subclass of Sub.

It seems to me, all you have accomplished here is to make it illegal
to call a class object directly as a function. If we were starting


From technical PoV*, yes.
Oh, and I fixed the super / new inconsistency.


I just don't see such an inconsistency in the current ES6 spec. draft. A
constructor is just a function that is usually called with a this value.
This is true whether it is called by the [[Constructor]] internal method
or via a super/super.constructor call. In either case, the primary
purpose of the constructor is to perform initialization actions upon the
this value. Where is the inconsistency?


(I claim that) in any circumstances, what developers want to express 
when writing `super(...args)` in the constructoro of SubFoo, is:
  On my this, which is now instance of SubFoo, I want the identical 
initialization code to be run, which `new Foo(...args)` would run to 
initialize newly created instance of Foo


That's not true. Because the spec is trying to serve two masters: F and 
F.prototype.constructor. It is impossible.


The fixed semantics of [[Construct]] for `class` ((1) above)  is fixing 
this by only serving one master: F.prototype.constructor (in line 3).



The only anomaly I see is that a handful of legacy built-ins do
completely different things for new operator originated calls in
contrast to regular function calls. There is no confusion in the spec.
about this and the mechanism for accomplishing it. However such split
behavior can't be declaratively defined in a normal function or class
declaration. In the other thread at
https://mail.mozilla.org/pipermail/es-discuss/2013-January/027864.html I
described how this split behavior an be procedurally described in such
declarations and also described how the same technique can be applied to
the offending built-in constructors (r any user defined class
constructor) to discriminate between initialization and called
behavior, even when called via super.

Yes, but it is a workaround.

Bonding identity of class with identity of constructor is not a law. It 
was just a workaround to make class without `class`. Nor, ultimately, 
can it be said it is preferred by the crowd (they have little other 
oossibility, it is not a preference but a legacy; similar to assigment 
is user preference over Object.define was not true, because of ES3 
legacy and ES5 being fairly new; I think this is the same pattern).


Physical separation allows it naturally, should one want it. By stopping 
serving F and serving F.prototype.constructor exclusively in new/super.



The only fix I saw that you made to super was that in you sketch
constructor methods defined via a class definition are only used for
instance initialization, so there doesn't need to be any code to
determine between initialization and call behavior. Constructor behavior
is always initialization behavior.


Yes, it is there. As a free bonus, btw. The main druver for the design 
was new/super two masters fixing. Then, later (Brendan Eich will not 
like this ;-) ) the beauty of breaking the tight coupling and not 
needing [[Call]] at all for object with [[Construct]].


There are in fact TWO freebies:
 - [[Call]] separated 

Re: Good-bye constructor functions?

2013-01-08 Thread Herby Vojčík



Kevin Smith wrote:

I think it's arguable either way.  I mean, the initializer-only behavior
advocated by Allen et al makes the class useless when called (as opposed
to new'd).

I don't think such an opinionated approach is really necessary.  One can
account for the funky behavior of the built-ins by providing an
additional call hook on the class, and leave everything else as is.
  When the class is called (as opposed to new'd), it would use that hook
instead of the constructor.  (super() would still use the parent's
constructor function.)

It could be supported with syntax like so:

 class C {
 static(...args) { /* call behavior */ }
 }


Read my reply to Allen, it shows more general solution there. In a few 
words, with class and constructor separated, you can specify what object 
should represent the class (and is given appropriate .prototype and 
[[Construct]]), would you want to (otherwise, plain object is created 
for you). One of the options is you can specify that a function should 
represent it:


  class C {
static function(...args) { /* call behaviour */ };
  }

though you can of course put any expression there. Another good 
candudate is {...} object literal.



I think one could also make a case that the default behavior for such a
hook would be to new the class, as some built-ins do (and as many
current JS classes attempt to do):

 class C {
 static(...args) { return new C(...args); }
 }


Yeah, in my proposal there is no default [[Call]] (have no reason for 
general object). But it is more general.



This seems like a pretty clean design to me.

{ Kevin }


Herby
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Good-bye constructor functions?

2013-01-08 Thread Brendan Eich

Herby Vojčík wrote:
In a few words, with class and constructor separated, you can specify 
what object should represent the class


Why? Where are the use-cases driving this, which goes beyond class as 
constructor function that can be called as well as new'ed?



(and is given appropriate .prototype and [[Construct]]),


By mutation of the result of an evaluated expression?


would you want to (otherwise, plain object is created for you).


What use-case?

One of the options is you can specify that a function should represent 
it:


  class C {
static function(...args) { /* call behaviour */ };
  }

though you can of course put any expression there. Another good 
candudate is {...} object literal. 


This is innovation beyond any cowpath or stable strawman we've promoted 
to Harmony in time for ES6. It goes beyond what we need, which Kevin 
pointed out succinctly: per-class @@call specialization.


/be
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Good-bye constructor functions?

2013-01-08 Thread Herby Vojčík



Brendan Eich wrote:

Herby Vojčík wrote:

In a few words, with class and constructor separated, you can specify
what object should represent the class


Why? Where are the use-cases driving this, which goes beyond class as
constructor function that can be called as well as new'ed?


This question is unfair: no one have use cases for this, when it was 
not possible at all in the language.


I'd ask the contrary*: what are the use case of tying class with its own 
constructor function?


*given the virtual scenario where those two are not tied


(and is given appropriate .prototype and [[Construct]]),


By mutation of the result of an evaluated expression?


Good question.

Well, that static Expr; was the second step, a possible cowpath when 
you allow the cows visit those green pastures beyond class tied to the 
constructor. So don't take it (the static syntax) as true proposal.


But to answer, yes, by modifying it.

In case of {} literal object, it's fine; no problem.
In case of function (...) {...} (or (...) = {}) also no problem: it 
is fresh creation and its [[Construct]] and .prototype may be changed 
accordingly.
In case of any other expression: you've been warned, but if you really 
want, you can (in case you put already existing class-like there, it 
fails, already having non-writable .prototype).



would you want to (otherwise, plain object is created for you).


What use-case?


Green pastures.


One of the options is you can specify that a function should represent
it:

class C {
static function(...args) { /* call behaviour */ };
}

though you can of course put any expression there. Another good
candudate is {...} object literal.


This is innovation beyond any cowpath or stable strawman we've promoted
to Harmony in time for ES6. It goes beyond what we need, which Kevin
pointed out succinctly: per-class @@call specialization.


This static syntax was an example of what can follow.
It was kind-of a carrot. Showing that you can do this separation very 
cleanly, if you have the class and constructor separated.


What I care for now, is the first step - opening the gates for 
[[Construct]] and decoupling it from need of [[Call]]able function.


Or at least the first half-step: the fixed [[Construct]] semantics, that 
fixes super doesn't run the same initialization code as new SuperClass 
would, and paving the way to, possibly, [[Construct]] on different objects.



/be


Herby
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Good-bye constructor functions?

2013-01-08 Thread Brendan Eich

Herby Vojčík wrote:

Brendan Eich wrote:

Herby Vojčík wrote:

In a few words, with class and constructor separated, you can specify
what object should represent the class


Why? Where are the use-cases driving this, which goes beyond class as
constructor function that can be called as well as new'ed?


This question is unfair: no one have use cases for this, when it was 
not possible at all in the language.


Nothing's unfair about designing by use-cases, and that's how a lot of 
the Web standards roll. Notorious counter-examples have gone off the 
rails by doing otherwise, but I won't try to sum of the problems so 
simplistically. Nevertheless, we need use-cases, preferably ones already 
approximated by library code or transpilers.


I'd ask the contrary*: what are the use case of tying class with its 
own constructor function?


Designing means saying no and leaving things out (N. Wirth, IIRC). 
That's point #1.


JS already has the prototypal pattern with constructor function as 
class, and that's what Harmony (now ES6) classes sugar. Point #2.


Stopping here. See my other reply on path dependency if you haven't yet.

/be
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Good-bye constructor functions?

2013-01-08 Thread Allen Wirfs-Brock

On Jan 8, 2013, at 12:45 AM, Herby Vojčík wrote:

 
 
 Allen Wirfs-Brock wrote:
 
 On Jan 7, 2013, at 4:09 PM, Herby Vojčík wrote:
 
 ...
 
 I just don't see such an inconsistency in the current ES6 spec. draft. A
 constructor is just a function that is usually called with a this value.
 This is true whether it is called by the [[Constructor]] internal method
 or via a super/super.constructor call. In either case, the primary
 purpose of the constructor is to perform initialization actions upon the
 this value. Where is the inconsistency?
 
 (I claim that) in any circumstances, what developers want to express when 
 writing `super(...args)` in the constructoro of SubFoo, is:
  On my this, which is now instance of SubFoo, I want the identical 
 initialization code to be run, which `new Foo(...args)` would run to 
 initialize newly created instance of Foo
 
 That's not true. Because the spec is trying to serve two masters: F and 
 F.prototype.constructor. It is impossible.
 
 The fixed semantics of [[Construct]] for `class` ((1) above)  is fixing this 
 by only serving one master: F.prototype.constructor (in line 3).

I agree with your above statement about initialization.  But I also content 
that is exactly what the current specification of super does within a 
constructor function (subject, of course to what the invoked methods actually 
are coded to do).  What I don't see  is why you think otherwise.  I need a 
clearer concrete explanation of what you see is the problem, prefably without a 
forward reference to what you think is the solution. 
 
 The only anomaly I see is that a handful of legacy built-ins do
 completely different things for new operator originated calls in
 contrast to regular function calls. There is no confusion in the spec.
 about this and the mechanism for accomplishing it. However such split
 behavior can't be declaratively defined in a normal function or class
 declaration. In the other thread at
 https://mail.mozilla.org/pipermail/es-discuss/2013-January/027864.html I
 described how this split behavior an be procedurally described in such
 declarations and also described how the same technique can be applied to
 the offending built-in constructors (r any user defined class
 constructor) to discriminate between initialization and called
 behavior, even when called via super.
 Yes, but it is a workaround.

Or, alternatively stated, it shows how the objective can be met without any 
further complicating the actual language.   That is arguably a good thing, not 
just a woprkaround

 ...
 The only fix I saw that you made to super was that in you sketch
 constructor methods defined via a class definition are only used for
 instance initialization, so there doesn't need to be any code to
 determine between initialization and call behavior. Constructor behavior
 is always initialization behavior.
 
 Yes, it is there. As a free bonus, btw. The main druver for the design was 
 new/super two masters fixing. Then, later (Brendan Eich will not like this 
 ;-) ) the beauty of breaking the tight coupling and not needing [[Call]] at 
 all for object with [[Construct]].
 
 There are in fact TWO freebies:
 - [[Call]] separated from [[Construct]]
 - you get default constructor for free; by not defining it explicitly.

Sorry, I still don't see it, you have to explain both the problem and your 
solution more concretely.


 
 When such freebies appear, for me this is the signal that someth8ing 
 clicks, eg., the design matches requirements very good.
 
 However, you don't support non-new invocation behavior, at all, on class
 objects so you can't use a class to self-host an implementation of, for
 example, RegExp. You also, don't do any thing to support correct
 
 Read the rest of the reply, please. The exact contrary is in fact true. I do.
 (meta question: why it is so often here that people are cutting the rest and 
 reply only on the first line dismissing the rest?)
 The proposal was first step: do class as plain objrct with [[Construct]], 
 thereby blessing class/constructor separation.
 The second step is: when plain object can do, anything can do (the only 
 question is how to specify it).
 
 It was sketched with more examples in the rest.

I did read the rest.  I don't see any provisions for calling the class object.  
Can you point me concretely  to where you define it?

Allen
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


RE: Good-bye constructor functions?

2013-01-08 Thread François REMY
 Nothing's unfair about designing by use-cases, and that's how a lot of
 the Web standards roll. 

I'm not sure I'm on topic because I didn't go throug the full thread, only a 
few mail, but what about the case of non-constructible DOM objects?

Until recently (still now on IE) you could only create a custom event via 
document.createEvent(CustomEvent) and the CustomEvent interface had no 
constructor (while CustomEvent.prototype do work and is the prototype of a 
custom event).

In IE10, document.createEvent(CustomEvent).constructor==CustomEvent but 
CustomEvent is not a function, it's just a holder for 
CustomEvent.prototype==Object.getPrototypeOf(customEv).

Best regards,
François  
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Good-bye constructor functions?

2013-01-08 Thread Allen Wirfs-Brock

On Jan 7, 2013, at 9:30 PM, Kevin Smith wrote:

 I think it's arguable either way.  I mean, the initializer-only behavior 
 advocated by Allen et al makes the class useless when called (as opposed to 
 new'd).

Not really.  If you want to, you can still do the same sort of ad hoc new/call 
discrimination in a class constructor that some JS programmers have 
historically done in constructor functions:

class Foo {
constructor() {
   if (this===undefined) return new Foo();
   this.isFoo = true
}
}

If you like this pattern you can still do it, plus I showed that it can still 
work with subclassing (including of built-ins) and super constructor calls. 

Whether this is a good or bad (or neutral) pattern is a separable issue. Also, 
we don't know which patterns will become widely adopted by JS programmers as 
class declaration come into wide use.  No doubt, at first, they will just 
follow either the JS patterns they already know or patterns they learned in 
other languages.  But in the long rung specific JS class declaration best 
practices will emerge.  None of us know exactly what they will be. 

 
 I don't think such an opinionated approach is really necessary.  One can 
 account for the funky behavior of the built-ins by providing an additional 
 call hook on the class, and leave everything else as is.  When the class is 
 called (as opposed to new'd), it would use that hook instead of the 
 constructor.  (super() would still use the parent's constructor function.)

I think any stylistic opinions are secondary.  The key point is that we can 
account for the funky behavior of built-ins and support their subclassing 
without anything in addition to what we already have in the ES6 spec.  Maybe in 
the future we may decide to add language to support this pattern but it isn't 
essential that it happens now.

 
 It could be supported with syntax like so:
 
 class C {
 static(...args) { /* call behavior */ }
 }
 
 I think one could also make a case that the default behavior for such a hook 
 would be to new the class, as some built-ins do (and as many current JS 
 classes attempt to do):
 
 class C {
 static(...args) { return new C(...args); }
 }
 
 This seems like a pretty clean design to me.

We haven't yet found consensus on any class syntax extensions beyond the basic 
max-min class syntax.  I suspect that it would be hard to get buy-in on the 
above syntax.   But let's look at how we could do it without new syntax and 
also examine some of the implications. 

We could accomplish pretty much the same thing via a @@call method on a class 
property.  To make this work we would have to make class constructors a new 
kind of exotic object (they currently are specified as ordinary function 
objects).  Their [[Call]] internal method could be defined approximately as the 
following JS pseudo code:

internal method [[Call]] (thisValue, argList) {
var ctor = this;  //the constructor object this internal method was called 
upon
var calledHandler = ctor.@@call;
if (calledHandler !== undefined) {
  if (isFunction(calledHandler)) 
  return calledHandler.[[Call]](thisValue,argList)
}
return the result of applying the ordinary function [[Call]] internal 
method to ctor with arguments thisValue and argList
}

So, C() woud invoke the  C.@@call method, if it was defined or inherited. These 
objects would also need to have a different [[Construct]] internal method so 
thatnew C() would invoke C using the body provide by the constructor body in 
the class declaration rather than going through the revised [[Call]] internal 
method.. 

That gives us the split dispatch for new/call. so now let's think about what 
happens with super calls during evaluation of both the constructor body and a 
@@call method.

First, I want to clarify that currently expressions of the form super() have no 
special semantics within constructor bodies.  In any concise method, super() is 
just shorthand for
super.methodName()
where methodName is the property key used in the concise method definition. 
Now consider:

import call_symbol ...;
class B {
   constructor() {console.log(B constructor)}
}
Object.mixin(B, {
[call_symbol] () {console.log(B @@call method)}
});
class C {
   constructor() {
  super();   //or super.constructor()
  console.log(C constructor);
   }
}  

So, using the current specification of super() and the new [[Call semantics 
above, this expresion:
new C()
will log: B @@call method, C constructor.

How do we fix this?  Presumably by giving special treatment to super() and 
super.constructor() (but only within concise constructor methods?? What 
should a super.constructor() call mean in other methods?).  What would that 
special treatment be?  It can't just be a [[Construct]] call to the result of 
the super-lookup  of constructor because that would allocated a new object, 
and use it as the this value which is not the 

Re: Good-bye constructor functions?

2013-01-08 Thread Kevin Smith
Allen,

Thanks for the analysis!  I think as long as the current design isn't
future-hostile with regard to this @@call hook, we're good.  Really,
declarative class-side methods would be a *much* bigger win than providing
support for the call/new split.

{ Kevin }
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Good-bye constructor functions?

2013-01-07 Thread Brendan Eich

Allen Wirfs-Brock wrote:

Even if we think we should discourage direct calls to class objects (I think 
I'm now in that camp)


(Why so?)

/be
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Good-bye constructor functions?

2013-01-07 Thread Brandon Benvie
I also agree with the sentiment. Splitting allocation from initialization
helps to clarify the two separate roles that constructors have
traditionally filled, and how a class could/should diverge from that. The
class itself is the thing that should allocate the new object, the
constructor initializes newly minted objects. Perhaps a middle ground with
the backward compatibility issue that awb mentions would be that calling a
class is always treated as constructing it, in that it always allocates a
new object if it's not receiving a newly created one from a subclass that's
in the process of initializing.


On Mon, Jan 7, 2013 at 6:24 PM, Brendan Eich bren...@mozilla.com wrote:

 Allen Wirfs-Brock wrote:

 Even if we think we should discourage direct calls to class objects (I
 think I'm now in that camp)


 (Why so?)

 /be

 __**_
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/**listinfo/es-discusshttps://mail.mozilla.org/listinfo/es-discuss

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Good-bye constructor functions?

2013-01-07 Thread Brandon Benvie
Although I already see flaws with that idea, since I just recently made use
of Constructor.call(existingInstance) to reinitialize an instance to
defaults. So nevermind that idea...


On Mon, Jan 7, 2013 at 6:31 PM, Brandon Benvie bran...@brandonbenvie.comwrote:

 I also agree with the sentiment. Splitting allocation from initialization
 helps to clarify the two separate roles that constructors have
 traditionally filled, and how a class could/should diverge from that. The
 class itself is the thing that should allocate the new object, the
 constructor initializes newly minted objects. Perhaps a middle ground with
 the backward compatibility issue that awb mentions would be that calling a
 class is always treated as constructing it, in that it always allocates a
 new object if it's not receiving a newly created one from a subclass that's
 in the process of initializing.


 On Mon, Jan 7, 2013 at 6:24 PM, Brendan Eich bren...@mozilla.com wrote:

 Allen Wirfs-Brock wrote:

 Even if we think we should discourage direct calls to class objects (I
 think I'm now in that camp)


 (Why so?)

 /be

 __**_
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/**listinfo/es-discusshttps://mail.mozilla.org/listinfo/es-discuss



___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Good-bye constructor functions?

2013-01-07 Thread Herby Vojčík



Allen Wirfs-Brock wrote:

OK, I ready you proposal.  I'll summaries it:

class Sub extends Super {
constructor (...args) {
super(...args);  //or super.constructor(...args)  because they mean the 
same thing.
   }
}

creates an (almost) ordinary object that is the initial value of the Sub binding.  The 
[[Prototype]] of Sub is the value of Super. Sub is created with a prototype property 
whose value is a new ordinary object whose [[Prototype]] values is Super.prototype.  Sub.prototype 
has a method property named constructor whose value is a super bound method function 
with the user specified body.  There is nothing special about this method, it it just like any 
other method defined in a class declaration.  In particular it does not have a [[Construct]] 
internal property.

The only thing exotic about Sub is that the object has a [[Construct]] internal 
method.  It does not have a [[Call]] internal method.  The definition of its 
[[Construct]] in almost JS pseudo code is:

   //internal method  this.[[Constructor]](argList):
   let newObj = this.@@create();  //eg Sub.@@create();
   let replacementObj = this.prototype.constructor.apply(newObj, argList);
   if (typeof replacementObj == object  replacementObj !== null) return 
replacementObj
   return newObj;

Implications:
Sub === Sub.prototype.constructor evaluates to false.
To create a new instance of Sub say:
new Sub()
The following is a TypeError, because Sub does not have a [[Call]] internal 
method:
   Sub()
The following is a TypeError, because Sub.prototype.constructor does not 
have a [[Construct]] internal method:
new Sub.prototype.constructor()
 Sub.prototype.constructor can be called directly or as a method invocation 
including via a super call a subclass of Sub.

It seems to me, all you have accomplished here is to make it illegal
to call a class object directly as a function. If we were starting


From technical PoV*, yes.
Oh, and I fixed the super / new inconsistency.


over that might be a reasonable design choice. But we have a legacy
to consider. Even if we think we should discourage direct calls to


Ignoring Foo.call(this) replacable by super, mostly, class is used for 
new Foo and for Foo.staticVar. I argued the change is big in its wider 
implication, even scary, maybe (but I see it as in fact minimal), but 
should not (imo) beat legacy much; because the fact of the tight 
coupling was not exploited so much.



class objects (I think I'm now in that camp) actually making it an
error seems like it may be too big of a step away from the legacy
conventions.


And there is no better time to do that step than now, when class is new 
construct in the language.


*There is more than narrow technical PoV.  By returning plain object 
with exotic [[Construct]], working in nearly every detail as a class, 
while affording not to be the constructor itself, you effective say 
openly You can use any [[Construct]]ified object as a class in ES6+. 
Gates are finally open.


It can be blessed by Reflect.makeClass(classObject, protoObject) or 
similar API.


It can bring lots of new patterns and cowpaths into the language.
If people don't want plain object to be the class, but their existing 
object x, they do

  Reflect.makeClass(x, (class {...}).prototype);

and they then can `new x`. They choose what they will use as x for new 
operator; because now class is one object and constructor is another.


For example, the criticized pattern of 'function that does differently 
for [[Call]] and [[Construct]]' could now be created as well. Just 
'makeClass' it.



The main message of this proposal is that beyond fixing super/new 
inconsistency, it opens new world for classes, not restricted by the 
legacy tightly bound class===constructor objects.


And by making class to return this kind of 'decoupled' classes, this 
widened view to who may be used as a class in new / extends? is 
effectively blessed.


You cannot open it later. Because there will be lagacy code that already 
uses `class`.


(I'd stress again, that, imo, that change is very little, too little for 
the fruits it can bear. Fix me if it breaks something critical)



Allen


Herby
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Good-bye constructor functions?

2013-01-07 Thread Herby Vojčík



Herby Vojčík wrote:

It can be blessed by Reflect.makeClass(classObject, protoObject) or
similar API.

It can bring lots of new patterns and cowpaths into the language.
If people don't want plain object to be the class, but their existing
object x, they do
Reflect.makeClass(x, (class {...}).prototype);


This can be in some version of `static` syntax in the future.  BUt it 
allows richer outcomes:


Not mere:
  class Foo {
...
static {
  // must be some predefined kind of body
}
  }

but instead:
  claas Foo {
...
static Expr;
  }

where Expr can be any object that would be [[Construct]]ified and bound 
to Foo. So it _can_ be {...} object literal, but it can be anything 
else, existing object that user want to class-ify, a function, ...



and they then can `new x`. They choose what they will use as x for new
operator; because now class is one object and constructor is another.

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Good-bye constructor functions?

2013-01-07 Thread Allen Wirfs-Brock

On Jan 7, 2013, at 4:09 PM, Herby Vojčík wrote:

 
 
 Allen Wirfs-Brock wrote:
 OK, I ready you proposal.  I'll summaries it:
 
 class Sub extends Super {
constructor (...args) {
super(...args);  //or super.constructor(...args)  because they mean 
 the same thing.
   }
 }
 
 creates an (almost) ordinary object that is the initial value of the Sub 
 binding.  The [[Prototype]] of Sub is the value of Super. Sub is created 
 with a prototype property whose value is a new ordinary object whose 
 [[Prototype]] values is Super.prototype.  Sub.prototype has a method 
 property named constructor whose value is a super bound method function 
 with the user specified body.  There is nothing special about this method, 
 it it just like any other method defined in a class declaration.  In 
 particular it does not have a [[Construct]] internal property.
 
 The only thing exotic about Sub is that the object has a [[Construct]] 
 internal method.  It does not have a [[Call]] internal method.  The 
 definition of its [[Construct]] in almost JS pseudo code is:
 
   //internal method  this.[[Constructor]](argList):
   let newObj = this.@@create();  //eg Sub.@@create();
   let replacementObj = this.prototype.constructor.apply(newObj, argList);
   if (typeof replacementObj == object  replacementObj !== null) 
 return replacementObj
   return newObj;
 
 Implications:
Sub === Sub.prototype.constructor evaluates to false.
To create a new instance of Sub say:
new Sub()
The following is a TypeError, because Sub does not have a [[Call]] 
 internal method:
   Sub()
The following is a TypeError, because Sub.prototype.constructor does not 
 have a [[Construct]] internal method:
new Sub.prototype.constructor()
 Sub.prototype.constructor can be called directly or as a method 
 invocation including via a super call a subclass of Sub.
 
 It seems to me, all you have accomplished here is to make it illegal
 to call a class object directly as a function. If we were starting
 
 From technical PoV*, yes.
 Oh, and I fixed the super / new inconsistency.

I just don't see such an inconsistency in the current ES6 spec. draft.  A 
constructor is just a function that is usually called with a this value.  This 
is true whether it is called by the [[Constructor]] internal method or via a 
super/super.constructor call.  In either case, the  primary purpose of the 
constructor is to perform initialization actions upon the this value.  Where is 
the inconsistency?

The only anomaly I see is that a handful of legacy built-ins do completely 
different things for new operator originated calls in contrast to regular 
function calls.   There is no confusion in the spec. about this and the 
mechanism for accomplishing it. However such split behavior can't be 
declaratively defined in a normal function or class declaration.   In the other 
thread at  
https://mail.mozilla.org/pipermail/es-discuss/2013-January/027864.html  I 
described how this split behavior an be procedurally described in such 
declarations and also described how the same technique can be applied to the 
offending built-in constructors (r any user defined class constructor) to 
discriminate between initialization and called behavior, even when called via 
super.

The only fix I saw that you made to super was that in you sketch constructor 
methods defined via a class definition are only used for instance 
initialization, so there doesn't need to be any code to determine between 
initialization and call behavior.  Constructor behavior is always 
initialization behavior.  

However, you don't support non-new invocation behavior, at all, on class 
objects so you can't use a class to self-host an implementation of, for 
example, RegExp.  You also, don't do any thing to support correct 
initialization of subclass of built-ins such as RegExp and Number that have 
different behaviors for called as constructor and called as function.

Allen



___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Good-bye constructor functions?

2013-01-07 Thread Allen Wirfs-Brock

On Jan 7, 2013, at 3:24 PM, Brendan Eich wrote:

 Allen Wirfs-Brock wrote:
 Even if we think we should discourage direct calls to class objects (I think 
 I'm now in that camp)
 
 (Why so?)

(Assuming you've already read 
https://mail.mozilla.org/pipermail/es-discuss/2013-January/027864.html)

The split constructor/function call behavior of things like Number and RegExp 
is specified as two distinct procedures that are distinguish based upon the 
type of invocation. Basally Number represents two different procedures and 
which one to invoke is contextually determined at the call site. The  
implementation of this can work by have an alternative entry point, or a 
special flag parameter associated with each such callable target.  Regardless 
of how it is actually implemented it amounts to the the function Number really 
representing two different procedures.

There is arguably some elegance in being able to use Number and a handful of 
others as both a coercion function and as a factory for new objects. However, 
as a general rule, it is probably not such a good idea to allow any arbitrary 
function to really be two procedure with arbitrarily different behaviors.  I 
suppose you could call it a form or overloading, sdomething which I'm also not 
particularly a big fan of.  Generally, I think programs are easier to 
understand if each named entity has only a single meaning. 

When you move from the ES spec. to ES code there currently is no way to 
declaratively express that we have a two procedure function. You have to have a 
single function body and try to use a conditional statement to choose between 
two different code paths within the same body.  But there also is no 
communications channel that conveys to the function body which sort of call 
context was used for the invocation.  In the post linked above, I showed how 
analysis of the this value along with careful branding of instances and 
initialization state can adequately duplicate the effective specified behavior 
of something like Number without direct communication of the nature of the call 
site.  This is similar to the manner in which ad hoc  parameter overloading is 
accomplished by JS programmers.  Again, like overloading, it can be 
accomplished and in a few situations it is desirable, but in general its 
probably something that should be avoided.  So, as a best practice I would 
generally discourage new/call over-loading.

We could try to formalize it. One way would be to make a flag available in the 
function body that indicating the invocation style (perhaps via  predeclared 
name in the same scope as the function name).  Another way would be to have a 
mechanism (perhaps a @@call or @@new private symbol named property of the 
function) to associate a second code body with each function.  However, either 
of these introduce the sort of super/new confusion that Herby and Brandon were 
concerned about. If @@call is the code body used for new, a super() call within 
it needs to call the super class constructor's @@new code instead of its @@call 
code like would be used anywhere else.  In addition it is adding both Es 
developer complexity and implementation complexity to potentially all calls.

So, I suggest:

1) Constructor  normally  should only be used to perform instance 
initialization.
2) In rare circumstances, overloading techniques can be used to make 
constructor functions choose between performing initialization or  
non-initialization tasks.  However this should be generally discouraged.

Allen___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Good-bye constructor functions?

2013-01-07 Thread Kevin Smith
I think it's arguable either way.  I mean, the initializer-only behavior
advocated by Allen et al makes the class useless when called (as opposed to
new'd).

I don't think such an opinionated approach is really necessary.  One can
account for the funky behavior of the built-ins by providing an additional
call hook on the class, and leave everything else as is.  When the class
is called (as opposed to new'd), it would use that hook instead of the
constructor.  (super() would still use the parent's constructor function.)

It could be supported with syntax like so:

class C {
static(...args) { /* call behavior */ }
}

I think one could also make a case that the default behavior for such a
hook would be to new the class, as some built-ins do (and as many current
JS classes attempt to do):

class C {
static(...args) { return new C(...args); }
}

This seems like a pretty clean design to me.

{ Kevin }
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Good-bye constructor functions?

2012-12-30 Thread Herby Vojčík

Hello,

thinking about class / new / super semantics and its problems, I came 
with an idea. Big change on the first look, but in fact, imho, not so 
big and making cleaner model.




tl;dr


Constructor function were workaround to specify constructor for a class 
without `class`. Now, having `class` nothing presribes the class being 
equivalent to its constructor. It always brought confusion and now with 
`constructor` empowered, it brings two-space problem. The `class` 
keyword can return plain objects, which have `[[Construct]]` calling the 
constructor of the class.




The rest is in https://gist.github.com/4413009. If you could please read 
it, it tries to explain and go a little into detail. I feel this is 
needed to do now, putting constraints away later would be harder, as I 
write below:




Conclusion
---

If `class` would decouple the value it produces (the class) from the 
constructor function, it would create cleaner and more future-friendly 
model of classes. Coupling class and its constructor function was a 
necessity in the past, but now they need not to be coupled. 
Class.prototype.constructor takes all the responsibility for 
initializing the instance. This change involves little risk (only pieces 
of code who actually [[Call]] the class for manually initializing it; 
super-constructor call can be replaced by `super` or 
`Superclass.prototype.constructor.{call,apply}`). The big spec pieces 
that involve creation of classes and their instances are already very 
near and the important pieces need just a few changes. The devil is in 
the details, the spec is still very 'constructor must be a 
function'-oriented, but this is mainly in textual parts, algorithms are 
already generic enough. One important reason to ponder `class` not being 
constructor function is not conserving this tight coupling which in 
world of ES6+ with `class` can be seen as antipattern; freeing the 
contraints now is much easier than doing it later, when this unnecessary 
coupling is repeated in `class` semantic.



Thanks, Herby
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Good-bye constructor functions?

2012-12-30 Thread Benoit Marchant
I'll take that occasion to mention that I feel ES doesn't need class at all.

We've been using Object.create in a way that allow us to create objects as 
prototypes for others, on these we add property descriptors, and then make 
instances off these prototypes without adding anything.

We use a create then init and never bother using a constructor function: pure, 
elegant, prototype inheritance.

This pattern works really well and is very natural for people with a class 
background.

Just saying...

Benoit

On Dec 30, 2012, at 11:47, Herby Vojčík he...@mailbox.sk wrote:

 Hello,
 
 thinking about class / new / super semantics and its problems, I came with an 
 idea. Big change on the first look, but in fact, imho, not so big and making 
 cleaner model.
 
 
 
 tl;dr
 
 
 Constructor function were workaround to specify constructor for a class 
 without `class`. Now, having `class` nothing presribes the class being 
 equivalent to its constructor. It always brought confusion and now with 
 `constructor` empowered, it brings two-space problem. The `class` keyword can 
 return plain objects, which have `[[Construct]]` calling the constructor of 
 the class.
 
 
 
 The rest is in https://gist.github.com/4413009. If you could please read it, 
 it tries to explain and go a little into detail. I feel this is needed to do 
 now, putting constraints away later would be harder, as I write below:
 
 
 
 Conclusion
 ---
 
 If `class` would decouple the value it produces (the class) from the 
 constructor function, it would create cleaner and more future-friendly model 
 of classes. Coupling class and its constructor function was a necessity in 
 the past, but now they need not to be coupled. Class.prototype.constructor 
 takes all the responsibility for initializing the instance. This change 
 involves little risk (only pieces of code who actually [[Call]] the class 
 for manually initializing it; super-constructor call can be replaced by 
 `super` or `Superclass.prototype.constructor.{call,apply}`). The big spec 
 pieces that involve creation of classes and their instances are already very 
 near and the important pieces need just a few changes. The devil is in the 
 details, the spec is still very 'constructor must be a function'-oriented, 
 but this is mainly in textual parts, algorithms are already generic enough. 
 One important reason to ponder `class` not being constructor function is not 
 conserving this tight coupling which in world of ES6+ with `class` can be 
 seen as antipattern; freeing the contraints now is much easier than doing it 
 later, when this unnecessary coupling is repeated in `class` semantic.
 
 
 Thanks, Herby
 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss