obsoleting the "new" keyword

# Peter Michaux (9 years ago)

The requirement that JavaScript needed to look like Java has long been lamented. One of the key "looks" was the "new" keyword. Many people don't like the use of the "new" keyword. Although "new" is here to stay, could we obsolete it when using a class sugar?

Peter

# Kris Zyp (9 years ago)

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1

I certainly hope not. A fundamental requirement of class sugar should be that it properly leverages "new". Kris

Peter Michaux wrote:

The requirement that JavaScript needed to look like Java has long been lamented. One of the key "looks" was the "new" keyword. Many people don't like the use of the "new" keyword. Although "new" is here to stay, could we obsolete it when using a class sugar?

Peter _______________________________________________ Es-discuss mailing list Es-discuss at mozilla.org, mail.mozilla.org/listinfo/es-discuss


Kris Zyp SitePen (503) 806-1841 sitepen.com -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - enigmail.mozdev.org

iEYEARECAAYFAkluHzcACgkQ9VpNnHc4zAxxjACcCGf4zgq0nBPboMntRgKZyz/u XNkAn12yb6ZX91jMgYaHZlA0Hsqv/JS4 =g37Z -----END PGP SIGNATURE-----

# Alex Russell (9 years ago)

I think I'm w/ Kris on this:

I'd be in favor of the "new" protocol being exposed in a programmatic
way, e.g.:

var instance = someClassName.new();

In the same way that callables have their execution protocol exposed
in call() and apply(). But I'd only favor this as a way to make the
semantics of "new" clearer, rather than deprecating it. The "new"
keyword makes at least one style of JavaScript much cleaner to read,
and unlike other languages the ES 3 "new" also doesn't burden
programmers with repetitive type notations on both sides of an
assignment.

# Mark S. Miller (9 years ago)

On Wed, Jan 14, 2009 at 9:19 AM, Peter Michaux <petermichaux at gmail.com>wrote:

The requirement that JavaScript needed to look like Java has long been lamented. One of the key "looks" was the "new" keyword. Many people don't like the use of the "new" keyword. Although "new" is here to stay, could we obsolete it when using a class sugar?

I agree. For all the desugaring of classes I've posted, the constructor is merely a function, not using "this", that constructs are returns a new instance. Thus, you get the same effect whether "new" is used on these or not. Both "Point(3, 5)" and "new Point(3, 5)" return the same thing.

# Erik Arvidsson (9 years ago)

The new keyword makes thing more readable and I agree with both Kris and Alex here that any class syntax we come up with should use new to look and feel like "classes" as used today in ES.

I'm fine with making this optional since it would allow us to strip "new " from the files we send over the wire ;-)

# Peter Michaux (9 years ago)

On Wed, Jan 14, 2009 at 9:40 AM, Mark S. Miller <erights at google.com> wrote:

On Wed, Jan 14, 2009 at 9:19 AM, Peter Michaux <petermichaux at gmail.com> wrote:

The requirement that JavaScript needed to look like Java has long been lamented. One of the key "looks" was the "new" keyword. Many people don't like the use of the "new" keyword. Although "new" is here to stay, could we obsolete it when using a class sugar?

I should have omitted "when using a class sugar". I'd like to see "new" completely unnecessary.

I agree. For all the desugaring of classes I've posted, the constructor is merely a function, not using "this", that constructs are returns a new instance. Thus, you get the same effect whether "new" is used on these or not. Both "Point(3, 5)" and "new Point(3, 5)" return the same thing.

Yes.

Needing "new" makes some things unnecessarily bulky.

var pts = getRows().map(function(r) {return new Point(r);});

verses just

var pts = getRows().map(Point);

Unfortunately some of the ES constructors behave differently when called without "new". This is a reasonably major problem with the language, in my opinion. Is there anything that can be done about this problem?

Peter

# Brendan Eich (9 years ago)

On Jan 14, 2009, at 10:51 AM, Peter Michaux wrote:

On Wed, Jan 14, 2009 at 9:40 AM, Mark S. Miller <erights at google.com>
wrote:

On Wed, Jan 14, 2009 at 9:19 AM, Peter Michaux <petermichaux at gmail.com

wrote:

The requirement that JavaScript needed to look like Java has long
been lamented. One of the key "looks" was the "new" keyword. Many people don't like the use of the "new" keyword. Although "new" is here to stay, could we obsolete it when using a class sugar?

I should have omitted "when using a class sugar". I'd like to see "new" completely unnecessary.

How could that work?

new Date !== Date()

new MyFunction != MyFunction() in general

I agree. For all the desugaring of classes I've posted, the
constructor is merely a function, not using "this", that constructs are returns a
new instance. Thus, you get the same effect whether "new" is used on
these or not. Both "Point(3, 5)" and "new Point(3, 5)" return the same thing.

Yes.

Needing "new" makes some things unnecessarily bulky.

var pts = getRows().map(function(r) {return new Point(r);});

verses just

var pts = getRows().map(Point);

As in C++, that is up to the purveyor of Point and users, who vote
with their fingers by using some better (more usable) Point if the
mandatory new (or lack of it) is a negative.

We are in a world of subjective value here, even though you and I know
our object values are right ;-). The standard will not remove 'new' in
any sense for functions of built-ins. Banning it from class
construction expressions seems unnecessary.

If we ever hope to bootstrap built-ins (not just "native" but also
"host", e.g. DOM) we need to allow custom new vs. invoke behavior as
ES4's metaprogramming model allowed.

Unfortunately some of the ES constructors behave differently when called without "new". This is a reasonably major problem with the language, in my opinion. Is there anything that can be done about this problem?

Not compatibly, and why are you ignoring the big difference new makes
with user-defined functions?

# Jeff Watkins (9 years ago)

Peter, our library makes extensive use of constructors without new as
a declarative way to build a class. Consider the example:

apple.EngravingGalleryController=
Class.create(coherent.ViewController, {

 tabs: coherent.ListView('div.tabs ul', {
                         selectedIndexBinding: 'selectedTab',
                         animated: 'true'
                     }),

 ...

});

Of course, you could also use coherent.ListView as a constructor to
create an explicit instance. Under the covers, the OOP mechanism
dispatches to a factory function which is used to ultimately create
the member.

This is a lot like the Python meta-programming stuff, except I don't
have an addToClass hook to use.

# Juriy Zaytsev (9 years ago)

On Jan 14, 2009, at 1:51 PM, Peter Michaux wrote:

[...]

Yes.

Needing "new" makes some things unnecessarily bulky.

var pts = getRows().map(function(r) {return new Point(r);});

verses just

var pts = getRows().map(Point);

This is indeed a frequent annoyance.

It wouldn't be so bad if there was Function.prototype.construct or
Function.prototype.new (or something along these lines).

Are there any plans to include such facility in ES3.1 (or any
objections against it?)

[...]

# Mark S. Miller (9 years ago)

On Wed, Jan 14, 2009 at 11:58 AM, Juriy Zaytsev <kangax at gmail.com> wrote:

Are there any plans to include such facility in ES3.1 (or any objections against it?)

Definitely not in ES3.1 -- it's too late.

Possibly for ES-Harmony, if someone posts a fleshed out proposal (hint hint ;)).

# David-Sarah Hopwood (9 years ago)

Kris Zyp wrote:

I certainly hope not. A fundamental requirement of class sugar should be that it properly leverages "new".

Why? Using a factory function is strictly more flexible than using 'new' (even in Java).

If 'new' is supported, then "new Foo(...)" should be equivalent to "Foo(...)" when Foo is defined using the class sugar, IMHO.

# Peter Michaux (9 years ago)

On Wed, Jan 14, 2009 at 11:58 AM, Juriy Zaytsev <kangax at gmail.com> wrote:

On Jan 14, 2009, at 1:51 PM, Peter Michaux wrote: [...]

Yes.

Needing "new" makes some things unnecessarily bulky.

var pts = getRows().map(function(r) {return new Point(r);});

verses just

var pts = getRows().map(Point);

This is indeed a frequent annoyance. It wouldn't be so bad if there was Function.prototype.construct or Function.prototype.new (or something along these lines). Are there any plans to include such facility in ES3.1 (or any objections against it?) [...]

Ding, ding, ding! I was hoping someone would suggest this but I don't know how it can work.

In order to be able to do the following, the Point.new function would need to be bound to Point and that is not the way properties work in JavaScript (which is unfortunate in some cases but beneficial in others.)

var pts = getRows().map(Point.new);

When Point.new is called inside map, the "this" object will be the global object, not the Point object.

Peter

# Brendan Eich (9 years ago)

On Jan 17, 2009, at 12:51 PM, Peter Michaux wrote:

In order to be able to do the following, the Point.new function would need to be bound to Point and that is not the way properties work in JavaScript (which is unfortunate in some cases but beneficial in others.)

var pts = getRows().map(Point.new);

When Point.new is called inside map, the "this" object will be the global object, not the Point object.

Does the |this| object matter? It need not, but if it did, then the
following should help.

People bind |this| all the time, and ES3.1 has
Function.prototype.bind. It's not hard to imagine extending this to
classes and defining new as a bound method of a class or function.

We also allow keywords as property names in JS1.7+ and did for ES4 --
this relaxation from current context-free reservation of identifiers
has been talked about for 3.1 too, and IIRC it was agreed to for
Harmony at last summer's Oslo meeting.

With the meta-programming APIs (Object.defineProperty, etc.) in ES3.1,
combined with JS1.7-ish keyword reservation, you could define such a
class new method:

// Assume classes as sugar definition of class C Object.defineProperty(C, 'new', { enumerable: false, configurable: false,
writable: false, value: function () { return C.apply(null,
arguments); }.bind(C) });

Of course this seems like much ado about nothing, because classes as
sugar mean C is a factory function, so you could just write

var pts = getRows().map(Point);

Again, if the class always constructs when invoked, why do we need .new?

One answer might be for classes that do not construct when invoked.
For better or worse, the core language and common embedding objects
have class constructor functions that do not construct when invoked
without operator new.

# Mark S. Miller (9 years ago)

On Sun, Jan 18, 2009 at 4:35 PM, Brendan Eich <brendan at mozilla.com> wrote:

We also allow keywords as property names in JS1.7+ and did for ES4 -- this relaxation from current context-free reservation of identifiers has been talked about for 3.1 too, and IIRC it was agreed to for Harmony at last summer's Oslo meeting.

It's in the ES3.1 grammar. In ES3.1, x.if is equivalent to x['if'], and ({if: x}) is equivalent to ({'if': x}).

# Brendan Eich (9 years ago)

On Jan 18, 2009, at 5:48 PM, Mark S. Miller wrote:

On Sun, Jan 18, 2009 at 4:35 PM, Brendan Eich <brendan at mozilla.com>
wrote:

We also allow keywords as property names in JS1.7+ and did for ES4
-- this relaxation from current context-free reservation of
identifiers has been talked about for 3.1 too, and IIRC it was
agreed to for Harmony at last summer's Oslo meeting.

It's in the ES3.1 grammar. In ES3.1, x.if is equivalent to x['if'],
and ({if: x}) is equivalent to ({'if': x}).

The other unreserved context in JS1.7 and later is after the
'function' keyword. Unambiguous, complementary, useful for some cases.
It's easy to tweak ES3.1's grammar to allow keywords in this context
too. Thoughts?

# Mark Miller (9 years ago)

2009/1/18 Brendan Eich <brendan at mozilla.com>:

The other unreserved context in JS1.7 and later is after the 'function' keyword. Unambiguous, complementary, useful for some cases. It's easy to tweak ES3.1's grammar to allow keywords in this context too. Thoughts?

It would be surprising to be able to say "function if(x) {return x;}" but not "if(33);". On property names, we symmetrically unreserve both the definition (by object literal) and the use (by ".").

# Brendan Eich (9 years ago)

On Jan 18, 2009, at 10:23 PM, Mark Miller wrote:

2009/1/18 Brendan Eich <brendan at mozilla.com>:

The other unreserved context in JS1.7 and later is after the
'function' keyword. Unambiguous, complementary, useful for some cases. It's
easy to tweak ES3.1's grammar to allow keywords in this context too.
Thoughts?

It would be surprising to be able to say "function if(x) {return x;}" but not "if(33);".

Surprising to a PL/1 fanboy :-P.

Seriously, if that is surprising, then is it surprising that

var obj = {if: 42}; with (obj) print(if);

doesn't work? Don't bust on 'with', the same issue arises in global
code with 'this' or equivalent ('global', 'window').

On property names, we symmetrically unreserve both the definition (by object literal) and the use (by ".").

Definition is just sugared assignment, in ES3 at any rate. You can't
assign

if = 4;

even though you can (in ES3.1 or JS1.7) say

this.if = 4;

at top level.

The best real-world example is when implemening something in JS that
has to match an interface across a language bridge with a reasonable
method name such as 'delete'. In such a case you could certainly use
an object initialiser or assignment (doesn't matter which), but you
couldn't give the function the intrinsic name 'delete'. Named
functions have their uses, not so much for recursive calls as for
better diagnostics and less inscrutable pretty-printing results.

Symmetry has less to do with any of this than utility. There are
several symmetries or relations here ("definition", assignment,
reference). Special-pleading for one kind of symmetry doesn't resolve
the argument from utility.

No one outside of the PL/1 community wants 'var var = var;' or other
such keywords in the unqualified reference sense to be possible. But
we've agreed (based on precedent) to two out of the three contexts in
which JS1.7 allows keywords to be used as identifiers. The use-case
for the third, function names, is strong enough that we implemented
it. I think it ought to be in 3.1, so I guess I'll put this on the f2f
agenda.

# Peter Michaux (9 years ago)

On Sun, Jan 18, 2009 at 4:35 PM, Brendan Eich <brendan at mozilla.com> wrote:

On Jan 17, 2009, at 12:51 PM, Peter Michaux wrote:

// Assume classes as sugar definition of class C Object.defineProperty(C, 'new', { enumerable: false, configurable: false, writable: false, value: function () { return C.apply(null, arguments); }.bind(C) });

Of course this seems like much ado about nothing, because classes as sugar mean C is a factory function, so you could just write

var pts = getRows().map(Point);

Again, if the class always constructs when invoked, why do we need .new?

One answer might be for classes that do not construct when invoked.

That is the answer.

For better or worse, the core language and common embedding objects have class constructor functions that do not construct when invoked without operator new.

By "obsolete" the "new" operator, I did not mean remove it from the language. I meant make using "new" the less preferred way to have a constructor function work as a constructor rather than a regular function call. In order to make "new" the less preferred way, a uniform way (possibly like String.new and Point.new) could be added to the language so that the "new" operator can stay in place but would be "community deprecated". Does that make sense?

Peter

# Brendan Eich (9 years ago)

On Jan 19, 2009, at 10:27 AM, Peter Michaux wrote:

Again, if the class always constructs when invoked, why do we
need .new?

One answer might be for classes that do not construct when invoked.

That is the answer.

Then how does one program what such classes do when they are invoked?
One would have to write C.new and C as a function:

class C(a, b) { static function new() { // constructor here... } // other methods here...

// Code for C invoked as a function here: return String(a) + b; }

At the Kona meeting we sketched alternatives for static public
methods. I'm using one such here (implicitly public), but the syntax
is not important -- except note how allowing reserved identifiers
after 'function' is important so that C.new can be called later.

For better or worse, the core language and common embedding objects
have class constructor functions that do not construct when invoked without
operator new.

By "obsolete" the "new" operator, I did not mean remove it from the language. I meant make using "new" the less preferred way

There's nothing short of removing new to make it less preferred than
some lengthier and more punctuated syntax, whatever your preference
might be.

to have a constructor function work as a constructor rather than a regular function call. In order to make "new" the less preferred way, a uniform way (possibly like String.new and Point.new) could be added to the language so that the "new" operator can stay in place but would be "community deprecated". Does that make sense?

Not really. First, there's a ton of new based code and books out
there. Second, other languages favor new C over C.new (counterexamples
exist but they won't move the entire community, or even a majority, as
far as a I can tell). Thirs, (new C) and (new C(a, b)) are as short as
if not shorter than (C.new()) and (C.new(a, b)). This plus the lighter
visual weight due to space instead of dot means operator new will
perdure -- I'll bet real money on it.

But again, since we can't remove operator new, there's not much point
in side bets or speculation. We should talk about metaprogrammability
-- invoking vs. constructing, the straw syntax shown above, etc.

# David-Sarah Hopwood (9 years ago)

Brendan Eich wrote:

On Jan 18, 2009, at 5:48 PM, Mark S. Miller wrote:

On Sun, Jan 18, 2009 at 4:35 PM, Brendan Eich <brendan at mozilla.com> wrote:

We also allow keywords as property names in JS1.7+ and did for ES4 -- this relaxation from current context-free reservation of identifiers has been talked about for 3.1 too, and IIRC it was agreed to for Harmony at last summer's Oslo meeting.

It's in the ES3.1 grammar. In ES3.1, x.if is equivalent to x['if'], and ({if: x}) is equivalent to ({'if': x}).

The other unreserved context in JS1.7 and later is after the 'function' keyword. Unambiguous, complementary, useful for some cases. It's easy to tweak ES3.1's grammar to allow keywords in this context too. Thoughts?

For it to be useful to define functions with names that are keywords, it would also have to be possible to reference those names (preferably in an arbitrary expression context, but in ES3.1 I don't see how they could be referenced at all, except in obscure corner cases involving the global object or 'with').

# Brendan Eich (9 years ago)

On Jan 20, 2009, at 12:06 AM, David-Sarah Hopwood wrote:

For it to be useful to define functions with names that are keywords, it would also have to be possible to reference those names (preferably in an arbitrary expression context, but in ES3.1 I don't see how they could be referenced at all, except in obscure corner cases involving the global object or 'with').

Please see followups in this thread.

# David-Sarah Hopwood (9 years ago)

Brendan Eich wrote:

On Jan 20, 2009, at 12:06 AM, David-Sarah Hopwood wrote:

For it to be useful to define functions with names that are keywords, it would also have to be possible to reference those names (preferably in an arbitrary expression context, but in ES3.1 I don't see how they could be referenced at all, except in obscure corner cases involving the global object or 'with').

Please see followups in this thread.

I don't see any relevant arguments in followups that would contradict the position above. The nearest thing to a relevant argument is:

The best real-world example is when implemening something in JS that has

to match an interface across a language bridge with a reasonable method

name such as 'delete'.

but I think that is only plausible for names of methods, i.e. properties; not function declarations.

# Brendan Eich (9 years ago)

On Jan 20, 2009, at 11:06 AM, David-Sarah Hopwood wrote:

I don't see any relevant arguments in followups that would
contradict the position above.

You replied selectively -- not nice.

The nearest thing to a relevant argument is:

The best real-world example is when implemening something in JS

that has

to match an interface across a language bridge with a reasonable

method

name such as 'delete'.

Since you deleted the rest of that paragraph, here it is again:

In such a case you could certainly use an object initialiser or
assignment (doesn't matter which), but you couldn't give the function
the intrinsic name 'delete'. Named functions have their uses, not so
much for recursive calls as for better diagnostics and less
inscrutable pretty-printing results.

but I think that is only plausible for names of methods, i.e.
properties; not function declarations.

This combined with deleting the relevant rest of the paragraph is a
non-sequitur. Yes, of course, property name contexts should unreserve
keywords. This is in ES3.1 already and not at issue, and rehashing it
does not address the bone of contention.

The intrinsic name of a function need not have anything to do with
property names where the property values reference the function (if
any -- the reference could be a downward funarg, obviously of a
different, non-reserved name). Diagnostics involving a call expression
should use the particular property name or other expression by which
the function was called, and do in quality implementations. But
diagnostics and debugger expressions used within the function's body
should be able to use the function's name, and if 'delete' is the best
name, it ought to be allowed.

It costs next to nothing for implementations or the spec to allow
ordinarily reserved keywords to be used after 'function', and it
benefits some users who already make use of this ability in JS1.7 and
up. The low cost and utilitarian benefit is the basis for
standardization.

This is not a huge issue, but neither is it negligable -- and the
manner in which you replied makes me want to spend more time on it
anyway, for rhetorical hygiene if nothing else. In other words, I'm
prepared to lose this argument and any other worth having, but only if
you actually respond to the argument I'm making.

# Peter Michaux (9 years ago)

On Wed, Jan 14, 2009 at 12:00 PM, Mark S. Miller <erights at google.com> wrote:

On Wed, Jan 14, 2009 at 11:58 AM, Juriy Zaytsev <kangax at gmail.com> wrote:

Are there any plans to include such facility in ES3.1 (or any objections against it?)

Definitely not in ES3.1 -- it's too late.

Possibly for ES-Harmony, if someone posts a fleshed out proposal (hint hint ;)).

As an idea, I just ran the following code in Firefox and it did do what I expected. It makes it possible to pass around a plain function object that will construct.

Function.prototype.defineGetter("make", function() { var thisC = this; var F = function() {}; return function() { F.prototype = thisC.prototype; var o = new F(); thisC.apply(o, arguments); return o; }; });

function Foo(a) { this.a = a; } Foo.prototype.greet = function() { alert('a foo says hello ' + this.a); };

var f = Foo.make('a'); f.greet();

(function(con) { var ff = con('asdf'); ff.greet(); })(Foo.make);


The above is not compatible with code written like the following

function Foo() { if (this instanceof Foo) { //... } else { //... } }

To be compatible with this type of constructor, the following works when there are no arguments to the constructor

Function.prototype.defineGetter("make", function() { var thisC = this; return function() { return new thisC(); }; });

Is there a way to write "make" without using eval so that the constructor is called with an arbitrary number of arguments?

Peter

# Mark S. Miller (9 years ago)

On Sat, Jan 24, 2009 at 9:17 PM, Peter Michaux <petermichaux at gmail.com>wrote:

As an idea, I just ran the following code in Firefox and it did do what I expected. It makes it possible to pass around a plain function object that will construct.

Function.prototype.defineGetter("make", function() { var thisC = this; var F = function() {}; return function() { F.prototype = thisC.prototype; var o = new F(); thisC.apply(o, arguments); return o; }; });

Won't work on Array, Date, RegExp, and Function, since o is created with [[Class]] "Object". But should work otherwise.

function Foo(a) { this.a = a; } Foo.prototype.greet = function() { alert('a foo says hello ' + this.a); };

var f = Foo.make('a'); f.greet();

(function(con) { var ff = con('asdf'); ff.greet(); })(Foo.make);


The above is not compatible with code written like the following

function Foo() { if (this instanceof Foo) { //... } else { //... } }

Why not? I just tried it on FF and it seems to work fine.

Is there a way to write "make" without using eval so that the constructor is called with an arbitrary number of arguments?

In Harmony you'll be able to use the "..." operator.

In ES3 and ES3.1, in order to handle Date, RegExp, and Array, the Cajita runtime includes Mike Samuel's "triangle of hackery":

/**

  • <tt>cajita.construct(ctor, [args...])</tt> invokes a simple function as
  • a constructor using 'new'. */ function construct(ctor, args) { ctor = asCtor(ctor); // This works around problems with (new Array()) and (new Date()) where // the returned object is not really a Date or Array on SpiderMonkey and // other interpreters. switch (args.length) { case 0: return new ctor(); case 1: return new ctor(args[0]); case 2: return new ctor(args[0], args[1]); case 3: return new ctor(args[0], args[1], args[2]); case 4: return new ctor(args[0], args[1], args[2], args[3]); case 5: return new ctor(args[0], args[1], args[2], args[3], args[4]); case 6: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5]); case 7: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); case 8: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); case 9: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); case 10: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]); case 11: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]); case 12: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11]); default: if (ctor.typeTag___ === 'Array') { return ctor.apply(USELESS, args); } var tmp = function tmp(args) { return ctor.apply(this, args); }; tmp.prototype = ctor.prototype; return new tmp(args); } }

The last part is similar to your make method, and was inspired by Crock's beget() pattern. Cajita does not whitelist the Function constructor. But for full ES3 or ES3.1, since "new Function(..)" is equivalent to "Function(..)", it would be easy to extend the triangle of hackery to handle the Function constructor.

Fortunately, once we have "...", the triangle of hackery will become unnecessary.

# Garrett Smith (9 years ago)

2009/1/24 Mark S. Miller <erights at google.com>:

On Sat, Jan 24, 2009 at 9:17 PM, Peter Michaux <petermichaux at gmail.com> wrote:

Is there a way to write "make" without using eval so that the constructor is called with an arbitrary number of arguments?

In Harmony you'll be able to use the "..." operator.

In ES3 and ES3.1, in order to handle Date, RegExp, and Array, the Cajita runtime includes Mike Samuel's "triangle of hackery":

No offense, but that is some ugly code.

For user defined function, you can "hide" the constructor function in a function then export a "create" method that calls "new".

var pkg = {}; (function(){ pkg.createC = createC; function createC(s) { return new C(s); } function C(s){ this.s = s; } })();

pkg.createC('s');

The constructor can still be gotten by the constructor property of a created instance, so it can be broken, but only if the user tries. Lots of plumbing there, too.

To supply varargs to that constructor, use a newApply function.

Function newApply, for a constructor C:

  1. create a dummy function F
  2. assign the C's prototype to F
  3. create a new F, as i
  4. call C.apply(i, arguments)

Garrett

# Mark S. Miller (9 years ago)

On Fri, Jan 30, 2009 at 12:19 AM, Garrett Smith <dhtmlkitchen at gmail.com>wrote:

No offense, but that is some ugly code.

Indeed. We wouldn't have written it if the language didn't force us to.

[...] To supply varargs to that constructor, use a newApply function.

Function newApply, for a constructor C:

  1. create a dummy function F
  2. assign the C's prototype to F
  3. create a new F, as i
  4. call C.apply(i, arguments)

Your step #3 still fails for the reason I stated earlier:

Won't work on Array, Date, RegExp, and Function, since o is created with [[Class]] "Object". But should work otherwise.

If your technique did work on, for example, Date, then we wouldn't need the ugly code. I suggest you try your ideas on Date.

# Garrett Smith (9 years ago)

On Fri, Jan 30, 2009 at 8:12 AM, Mark S. Miller <erights at google.com> wrote:

On Fri, Jan 30, 2009 at 12:19 AM, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

No offense, but that is some ugly code.

Indeed. We wouldn't have written it if the language didn't force us to.

[...] To supply varargs to that constructor, use a newApply function.

Function newApply, for a constructor C:

  1. create a dummy function F
  2. assign the C's prototype to F
  3. create a new F, as i
  4. call C.apply(i, arguments)

Your step #3 still fails for the reason I stated earlier:

Won't work on Array, Date, RegExp, and Function, since o is created with [[Class]] "Object". But should work otherwise.

It would not work for Date, even if F were changed to Date. Example:

var d = new Date; Date.apply(d, [1999, 11]);

Result is current date: "Fri Jan 30 2009 10:42:08 GMT-0800 (PST)"

The applied object's [[Class]] is "Date" here. The problem is not because the applied object's [[Class]] is "object". The reason it doesn't work is that Date(), when called as a function, ignores the arguments it is given and returns the current Date.

For creating Function, it would not work for another reason.

function f(){} Function.apply(f, "a", "alert(a)");

That would not result in changing f. Instead, it would return a new Function object.

It doesn't work for built-ins or Host object.

Garrett