13.2.2 [[Construct]], constructor, and [[Class]] (was __proto__)

# Garrett Smith (18 years ago)

On 9/22/07, liorean <liorean at gmail.com> wrote:

On 22/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

What I've found is that it's always giving wrong constructor property with inheritance chains.

A <-- B <-- C c = (new C).constructor;// A

<snip> I meant an enumerable superclass property!

You get that if you do the following:

function A(){}
function B(){}
B.prototype=new A;
function C(){}
C.prototype=new B;

Because if you do that, you replace the prototype containing the original constructor property (e.g. a reference back to the function C) with an instance of another constructor (e.g. B), but that instance doesn't have the constructor property that the original prototype had. If you want to keep the constructor properties, you need to do that manually. (With the obvious result that then the constructor property will be enumerable. Which can be changed through adding a call on propertyIsEnumerable in ES4.)

Ah, sorry, I said a few things wrong!

  1. constructor is DontEnum.13.2 - bclary.com/2004/11/07/#a-13.2 (It's the user-defined superclass property that is enumerable.)

  2. The constructor property should be on the object instance created by the function.

<snip>

How about a constructor property on the function instance?

  1. (new function(){}).constructor should be Function.

But you understood what I meant even though I said it wrong. I meant to say that the object instance's constructor property should be the Function that "new" was called on.

Which could be done, of course, it should be a simple thing to add that in the algorithm for [[Construct]]. But then we have the question of what to do with constructors that return other objects than that set up by steps 1 through 5 of the [[Construct]] algorithm. A constructor can return other objects, you know. <snip>

In ES4, it is a syntax error to specify a result type of a constructor. If someone is using new F, the constructor property of the instance should be F.

(new F).constructor; // should be F.

The constructor property should match the [[Construct]] property. This should happen right before the prototype. Here's 13.2.2 with my edits:

13.2.2 [[Construct]]

When the [[Construct]] property for a Function object F is called,

the following steps are taken:

1. Create a new native ECMAScript object.
2. Set the [[Class]] property of Result(1) to "Object".

--> ∆ set the [[Class]] of o to reflect the name F <--

3. Get the value of the prototype property of F.

   -->  Set the constructor property of Result(1) to F  <--

4. If Result(3) is an object, set the [[Prototype]] property of

Result(1) to Result(3). 5. If Result(3) is not an object, set the [[Prototype]] property of Result(1) to the original Object prototype object as described in 15.2.3.1. 6. Invoke the [[Call]] property of F, providing Result(1) as the this value and providing the argument list passed into [[Construct]] as the argument values. 7. If Type(Result(6)) is Object then return Result(6). 8. Return Result(1).

∆ Note: Although allowed in ES3, Functions used as constructors should not return a value. (reword)

probably wouldn't hurt much code out there.

What could it hurt? What would get broken?

Benefits:

  1. can crawl up the constructors without having to bake the functionality into your library,
  2. Doesn't force clients to use a non-standard fix.
  3. [[class]] matches constructor property

The flip side of (2) is that if it stays, a client of a library that "fixes" the constructor property may have objects created by an in-house or another third party library where the library doesn't fix the constructor property.

The constructor property is modifiable, but you cant count on third party libraries using the same modification (I call it a nonstandard "fix") to the constructor property.

ES4 ref impl seems a bit off:

(new function F(){}).constructor [function Function]

new Date(9e9).constructor [class Class]

1['constructor'] [class Class]

It appears that es4 ref impl has the correct result for instancof on primitives

All are true in ES4 and false in ES3: true instanceof Boolean "oo" instanceof String 2 instanceof Number null instanceof Object NaN instanceof Number Number.Infinity instanceof Number

I think the change is correct. if typeof b == "boolean", b instanceof boolean seems like it must be true.

I would like to understand why it was not working right in ES3-, if someone can explain.

Garrett

# liorean (18 years ago)

On 22/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

What I've found is that it's always giving wrong constructor property with inheritance chains.

A <-- B <-- C c = (new C).constructor;// A

<snip> I meant an enumerable superclass property!

On 9/22/07, liorean <liorean at gmail.com> wrote:

You get that if you do the following:

function A(){}
function B(){}
B.prototype=new A;
function C(){}
C.prototype=new B;

Because if you do that, you replace the prototype containing the original constructor property (e.g. a reference back to the function C) with an instance of another constructor (e.g. B), but that instance doesn't have the constructor property that the original prototype had. If you want to keep the constructor properties, you need to do that manually. (With the obvious result that then the constructor property will be enumerable. Which can be changed through adding a call on propertyIsEnumerable in ES4.)

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

Ah, sorry, I said a few things wrong!

  1. constructor is DontEnum.13.2 - bclary.com/2004/11/07/#a-13.2 (It's the user-defined superclass property that is enumerable.)

If I wasn't clear on that, the that's the difference between the one that the implementation would set up for you and the one you'd have to create manually to preserve the constructor chain in ES3. And ES4 allows for making it non-enumerable manually, so in ES4 code using the prototypal inheritance model could be rid of this problem, albeit with a slight cludgyness added to the code because developers actually have to both add the property to an instance and set it to be non-enumerable.

  1. The constructor property should be on the object instance created by the function.

That argument I agree with. It should be on the instance and not the prototype.

On 22/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

How about a constructor property on the function instance?

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

  1. (new function(){}).constructor should be Function.

I agree. And in ES3 it is, unless the function either:

  • Returns another object than that it was passed from [[Construct]]
  • Creates a constructor property on the this object that is not a function
  • Has it's prototype overwritten

A disagreement of terminology I think. If you ask me, a function instance is a function object. When using a function instance as a constructor, you create an instance of that constructor (== function instance) which is a plain, ordinary, mundane, normal, run-of-the-mill, typical object. (Agh, ran out of synonyms!)

On 9/22/07, liorean <liorean at gmail.com> wrote:

Which could be done, of course, it should be a simple thing to add that in the algorithm for [[Construct]]. But then we have the question of what to do with constructors that return other objects than that set up by steps 1 through 5 of the [[Construct]] algorithm. A constructor can return other objects, you know.

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

In ES4, it is a syntax error to specify a result type of a constructor. If someone is using new F, the constructor property of the instance should be F.

If it's a constructor in the ES4 introduced classical inheritance sense, I have no arguments against that. And neither do I have any strong arguments against it for type annoted functions. The rather weak argument I do have against the latter is that it makes it harder to simply add type annotations to old type consistent ES3 code and have it work. But for ES3 and real web compatibility, I don't think changing the algorithm to not allow ordinary ES3 functions used as constructors to return objects other than the one set up by [[Construct]] will work.

Take a look at this article for example: uri:http://www.digital-web.com/articles/objectifying_javascript/

It's only one of many articles, tutorials and scripting tips and tricks I've seen that uses the new keyword that way.

I've actually seen developers arguing that it's a proper way of using the new keyword since the new keyword makes it clear you're constructing an object up front instead of using regular function calls that only make it obvious after you've read the function body. Typical example is the argument that "new function(...){...}(...)" makes it's usage as setting up an object more clear than "(function(...){...}(...))" or "(function(...){...})(...)".

It's not an argument I generally agree with, but I see it around, and my impression is that it's getting more common. A few years ago I saw it only once or twice. Mostly, I think this trend is due to far larger amounts of advanced scripting being done, and as an effect more interest in using OO constructs.

(new F).constructor; // should be F.

The constructor property should match the [[Construct]] property. This should happen right before the prototype.

I agree, it should. Before or after is not important. It would override the one in the prototype chain in any case, since that's the order property lookup will use.

On 9/22/07, liorean <liorean at gmail.com> wrote:

probably wouldn't hurt much code out there.

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

What could it hurt? What would get broken?

Any code that actually relies on the constructor chain being broken (Such as checking for c.constructor===A&&c.propertyInheritedOnlyFromC because c.constructor===C was false when the developer tried that, in your original example.) Remember that a lot of developers don't code to the spec, they code to browser behaviour. If browser behaviour doesn't make sense, they do workarounds. They could have made better workarounds than that if they were aware of the cause of the actual problem, but most of them are not.

ES4 ref impl seems a bit off:

(new function F(){}).constructor [function Function]

new Date(9e9).constructor [class Class]

1['constructor'] [class Class]

Seems a bit broken, yes...

It appears that es4 ref impl has the correct result for instancof on primitives

All are true in ES4 and false in ES3: true instanceof Boolean "oo" instanceof String 2 instanceof Number null instanceof Object NaN instanceof Number Number.Infinity instanceof Number

I think the change is correct. if typeof b == "boolean", b instanceof boolean seems like it must be true.

A bugfix, IIRC.

# Brendan Eich (18 years ago)

On Sep 23, 2007, at 8:59 AM, liorean wrote:

  1. The constructor property should be on the object instance
    created by the function.

That argument I agree with. It should be on the instance and not
the prototype.

The reason for the original prototype-owned constructor was to afford
a back-pointer from prototype to constructor function without
imposing a per-instance property (which could be optimized to be
shared where possible, overridden where desired -- but at some cost
in implementation complexity).

I'm not convinced it's worth changing this for ES4. Anyway it is very
late to have a new proposal -- we are finalizing proposals next week
at the face-to-face meeting.

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

  1. (new function(){}).constructor should be Function.

I agree. And in ES3 it is, unless the function either:

No:

js> (new function(){}).constructor

function () { } js> function C(){}

js> new C().constructor

function C() { }

in no case is the value of (new function(){}).constructor Function.

  • Returns another object than that it was passed from [[Construct]]
  • Creates a constructor property on the this object that is not a
    function
  • Has it's prototype overwritten

Good points.

But for ES3 and real web compatibility, I don't think changing the algorithm to not allow ordinary ES3 functions used as constructors to return objects other than the one set up by [[Construct]] will work.

Right, this will break the web. Tucker can weigh in on the
workarounds OpenLaszlo needed to cope with the instance of this bug
in Flash (AS2, and I think AS3 still, do not let a function return a
different object from the one passed in as this when called via new).

ES4 ref impl seems a bit off:

(new function F(){}).constructor [function Function]

This is on file: bugs.ecmascript.org/ticket/64

new Date(9e9).constructor [class Class]

I don't see this one on file -- someone please file it! Thanks.

1['constructor'] [class Class]

Seems a bit broken, yes...

This one may be covered by other tickets but filing it won't hurt.

It appears that es4 ref impl has the correct result for instancof
on primitives

All are true in ES4 and false in ES3: true instanceof Boolean "oo" instanceof String 2 instanceof Number null instanceof Object NaN instanceof Number Number.Infinity instanceof Number

I think the change is correct. if typeof b == "boolean", b instanceof boolean seems like it must be true.

A bugfix, IIRC.

Incompatbile enough that we are not taking the chance -- we are
changing this to match ES1-3, and to avoid boolean <: Boolean etc.

# Garrett Smith (18 years ago)

On 9/23/07, liorean <liorean at gmail.com> wrote:

On 22/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

What I've found is that it's always giving wrong constructor property with inheritance chains.

A <-- B <-- C c = (new C).constructor;// A

<snip> I meant an enumerable superclass property!

On 9/22/07, liorean <liorean at gmail.com> wrote:

You get that if you do the following:

function A(){}
function B(){}
B.prototype=new A;
function C(){}
C.prototype=new B;

Because if you do that, you replace the prototype containing the original constructor property (e.g. a reference back to the function C) with an instance of another constructor (e.g. B), but that instance doesn't have the constructor property that the original prototype had. If you want to keep the constructor properties, you need to do that manually. (With the obvious result that then the constructor property will be enumerable. Which can be changed through adding a call on propertyIsEnumerable in ES4.)

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

Ah, sorry, I said a few things wrong!

  1. constructor is DontEnum.13.2 - bclary.com/2004/11/07/#a-13.2 (It's the user-defined superclass property that is enumerable.)

If I wasn't clear on that, the that's the difference between the one that the implementation would set up for you and the one you'd have to create manually to preserve the constructor chain in ES3. And ES4 allows for making it non-enumerable manually, so in ES4 code using the prototypal inheritance model could be rid of this problem, albeit with a slight cludgyness added to the code because developers actually have to both add the property to an instance and set it to be non-enumerable.

Function objects get a non-enumerable constructor. function F(){}; F.constructor === Function; // true F.prototype.hasOwnProperty('constructor'); //true F.prototype.propertyIsEnumerable("constructor"); // false.

Object instances don't, unless it's a prototype object created by [[construct]] (new F).constructor === F.constructor; // true. Undesirable

This works fine for shallow inheritance Objects don't get a constructor ({}).constructor === Object.prototype.constructor; // True.

Built in objects get a constructor in the prototype: Date.prototype.constructor === Date; // True.

  1. The constructor property should be on the object instance created by the function.

That argument I agree with. It should be on the instance and not the prototype.

Which is different from the way built ins work, but seems OK.

On 22/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

How about a constructor property on the function instance?

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

  1. (new function(){}).constructor should be Function.

I agree. And in ES3 it is, unless the function either:

  • Returns another object than that it was passed from [[Construct]]
  • Creates a constructor property on the this object that is not a function
  • Has it's prototype overwritten

function Dec(){}

var Expr = function(){};

var e = new Expr();

b.constructor; // Expr

When there is an anonymous constructor, we have the ability to get at the constructor property.

function Animation(element){ var looped = 0; var e = element;

function construct() { this.loopCount = function() { return looped; } this.loop = function() { looped++; } } return new construct(); }

new new Animation().constructor().constructor; // construct

A disagreement of terminology I think. If you ask me, a function instance is a function object. When using a function instance as a constructor, you create an instance of that constructor (== function instance) which is a plain, ordinary, mundane, normal, run-of-the-mill, typical object. (Agh, ran out of synonyms!)

F is a Function instance f is a function instance

The terminology is confusing.

function F(){} var f = new F; f instanceof F; // true F instanceof Function; // true

typeof f == "object"; // true. typeof F == "function"; // true.

f.constructor === F; // true F.constructor === Function;/ true.

f instanceof F; // true F instanceof Function; // true

typeof f; // "object" typeof F; // "function"

# liorean (18 years ago)

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

  1. (new function(){}).constructor should be Function.

On Sep 23, 2007, at 8:59 AM, liorean wrote:

I agree. And in ES3 it is, unless the function either:

On 23/09/2007, Brendan Eich <brendan at mozilla.org> wrote:

No:

js> (new function(){}).constructor function () { } js> function C(){} js> new C().constructor function C() { }

Ah, my mistake there, was thinking of (function(){}).constructor for a moment there.

in no case is the value of (new function(){}).constructor Function.

Thinking about it with the new keyword in mind, I just realise that what Garrett suggested makes no sense anyway - the function object is the constructor. The function object is an instance of Function, but the resulting object is an instance of the function object. Making the object have Function as it's constructor property breaks the prototype-constructor relationship.

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

It appears that es4 ref impl has the correct result for instancof on primitives

On Sep 23, 2007, at 8:59 AM, liorean wrote:

A bugfix, IIRC.

On 23/09/2007, Brendan Eich <brendan at mozilla.org> wrote:

Incompatbile enough that we are not taking the chance -- we are changing this to match ES1-3, and to avoid boolean <: Boolean etc.

Sad to hear that, but I guess compatibility will have to rule here.

# Garrett Smith (18 years ago)

On 9/23/07, liorean <liorean at gmail.com> wrote:

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

  1. (new function(){}).constructor should be Function.

On Sep 23, 2007, at 8:59 AM, liorean wrote:

I agree. And in ES3 it is, unless the function either:

On 23/09/2007, Brendan Eich <brendan at mozilla.org> wrote:

No:

js> (new function(){}).constructor function () { } js> function C(){} js> new C().constructor function C() { }

Ah, my mistake there, was thinking of (function(){}).constructor for a moment there.

in no case is the value of (new function(){}).constructor Function.

It shouldn't be, but it is in OSX Ref Impl. (I did not build this).

js> (new function(){}).constructor [function Function]

Thinking about it with the new keyword in mind, I just realise that what Garrett suggested makes no sense anyway - the function object is the constructor. The function object is an instance of Function, but the resulting object is an instance of the function object. Making the object have Function as it's constructor property breaks the prototype-constructor relationship.

Correctly corrected.

In the following example:

function F(){} F.prototype.constructor = F; F.prototype.propertyIsEnumerable("constructor"); // false, it's set to {DontEnum} in step 10. Object.prototype. F.prototype.constructor === F; //true F.prototype = { constructor : F }; F.prototype.constructor === F; // false F.prototype.propertyIsEnumerable("constructor"); // true, now F.prototype is an object

F.prototype is assigned to a new Object. The new Object goes through [[construct]] getting its [[class]] property to Object. Object instances get the constructor property from Object.prototype. The only exception being prototype properties of Function objects, where the constructor is flagged DontEnum.

The constructor property of an object doesn't reflect the constructor that called it.

Garrett

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

It appears that es4 ref impl has the correct result for instancof on primitives

On Sep 23, 2007, at 8:59 AM, liorean wrote:

A bugfix, IIRC.

On 23/09/2007, Brendan Eich <brendan at mozilla.org> wrote:

Incompatbile enough that we are not taking the chance -- we are changing this to match ES1-3, and to avoid boolean <: Boolean etc.

Sad to hear that, but I guess compatibility will have to rule here.

So it's going back, to (true instanceof Boolean == false), huh ?

# liorean (18 years ago)

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

Function objects get a non-enumerable constructor. function F(){}; F.constructor === Function; // true F.prototype.hasOwnProperty('constructor'); //true F.prototype.propertyIsEnumerable("constructor"); // false.

Of course.

Object instances don't, unless it's a prototype object created by [[construct]] (new F).constructor === F.constructor; // true. Undesirable

Wrong, it's false. (new F).constructor === F.constructor; // => false (new F).constructor === F.prototype.constructor; // => true

This works fine for shallow inheritance Objects don't get a constructor

In what way do you mean they don't? Their constructor is the Object object, as you show next:

({}).constructor === Object.prototype.constructor; // True.

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

  1. The constructor property should be on the object instance created by the function.

On 9/23/07, liorean <liorean at gmail.com> wrote:

That argument I agree with. It should be on the instance and not the prototype.

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

Which is different from the way built ins work, but seems OK.

Well, at least if you want to make sense out of the prototypal inheritance scheme. The built ins are all single level IIRC,k and don't need to set up their prototype relationship in user code. A prototype system that didn't just clobber the old prototype when setting up prototype chains maybe could have done it better. But that won't happen in ECMAScript.

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

  1. (new function(){}).constructor should be Function.

On 9/23/07, liorean <liorean at gmail.com> wrote:

I agree.

Actually I don't agree here, see my reply to Brendan earlier.

And in ES3 it is, unless the function either:

And I was thinking of (function(){}).constructor here, not (new function(){}).constructor, when I said in ES3 it is. It isn't, which is proper since the object is constructed by the anonymous function object, not the Function object.

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

When there is an anonymous constructor, we have the ability to get at the constructor property.

I don't see this as a problem - the constructor property should be the function that actually constructed the object. Since ES3 allows any value (except eval, I think) to be assigned to any variable (except read only ones and those with special setters), the difference between function declarations and function expressions is that declarations are by default accessible through a variable name only, and function expressions are by default accessible through the return value of the expression only. There's no way to actually tell a function derived from a function expression and a function derived from a function declaration apart after the fact. (Well, except for that function expressions make the name optional.)

So, if we want to be able to get at constructors at all, we can't distinguish between how functions are derived - either we provide the functionality, or we don't.

function Animation(element){ var looped = 0; var e = element;

function construct() { this.loopCount = function() { return looped; } this.loop = function() { looped++; } } return new construct(); }

new new Animation().constructor().constructor; // construct

Sure. It's a closure, it exposes a property it's told to expose. (If you use the new keyword, that it exposes the function object as the constructor property of the constructed object should be expected.) You can do this without the new keyword if you want to not expose the function object, or use the delete keyword to explicitly remove it.

On 9/23/07, liorean <liorean at gmail.com> wrote:

A disagreement of terminology I think. If you ask me, a function instance is a function object. When using a function instance as a constructor, you create an instance of that constructor (== function instance) which is a plain, ordinary, mundane, normal, run-of-the-mill, typical object. (Agh, ran out of synonyms!)

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

F is a Function instance f is a function instance

The terminology is confusing.

F is an instance of Function f is an instance of F

Function is a function object F is a function object f is an object

As I see it, the meaning of "function instance" is an object that is function-like, in other words a function object or a special host object (like Function.prototype, which is a function but not an instance of Function).

# Garrett Smith (18 years ago)

On 9/23/07, liorean <liorean at gmail.com> wrote:

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

Function objects get a non-enumerable constructor. function F(){}; F.constructor === Function; // true F.prototype.hasOwnProperty('constructor'); //true F.prototype.propertyIsEnumerable("constructor"); // false.

Of course.

F.prototype = { constructor : F } F.prototype.propertyIsEnumerable("constructor");

Object instances don't, unless it's a prototype object created by [[construct]] (new F).constructor === F.constructor; // true. Undesirable

Wrong, it's false. (new F).constructor === F.constructor; // => false (new F).constructor === F.prototype.constructor; // => true

Right.

This works fine for shallow inheritance Objects don't get a constructor

In what way do you mean they don't? Their constructor is the Object object, as you show next:

({}).constructor === Object.prototype.constructor; // True.

({}).hasOwnProperty("constructor"); //false.

{} is the same as new Object;

new Object goes through [[construct]]

The instance does not get a constructor property. No object instance does. Well, none except objects that are prototype properties that went through [[construct]]. This is confusing and makes the language less clear to developers. It confuses me.

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

  1. The constructor property should be on the object instance created by the function.

On 9/23/07, liorean <liorean at gmail.com> wrote:

That argument I agree with. It should be on the instance and not the prototype.

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

Which is different from the way built ins work, but seems OK.

Well, at least if you want to make sense out of the prototypal inheritance scheme. The built ins are all single level IIRC,k and don't need to set up their prototype relationship in user code. A prototype system that didn't just clobber the old prototype when setting up prototype chains maybe could have done it better. But that won't happen in ECMAScript.

I don't see a problem.

var d = new Date; d.constructor == Date; // true d.hasOwnProperty('constructor'); // false

The proposed change would have the result of: d.hasOwnProperty('constructor'); // true d.isPropertyEnumerable('constructor'); // false

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

  1. (new function(){}).constructor should be Function.

On 9/23/07, liorean <liorean at gmail.com> wrote:

I agree.

Actually I don't agree here, see my reply to Brendan earlier.

Right.

On 23/09/2007, Garrett Smith <dhtmlkitchen at gmail.com> wrote:

When there is an anonymous constructor, we have the ability to get at the constructor property.

I don't see this as a problem -

Right. Whether or not the Function object has a name is irrelevant.

the constructor property should be the

function that actually constructed the object.

Exactly. That's what I'm talking about.

The fact that (new C).constructor === A; is true, by default of the language, is counterintuitive.

[[construct]] gives a function instance a special prototype property. That prototype property is an object, but not just an object, a special object -- one that has a constructor property that is specially flagged DontEnum. You lose that property the moment you give a prototype property to F. Well, if the prototype property you give to F is created through [[construct]], you don't.

You have to be careful.

F=function(){}; new F().constructor == F; // true. F.propertyIsEnumerable("prototype"); //true, Futhark and JScript say false. F.prototype = {}; new F().constructor == F; // false. F.prototype.constructor = F; F.prototype.propertyIsEnumerable("constructor"); // true, JScript says false.

var complaint = false; for( var prop in new F ) complaint = true;

if(!complaint) alert('failure'); The browser support is pretty inconsistent, too.

So, if we want to be able to get at constructors at all, we can't distinguish between how functions are derived - either we provide the functionality, or we don't.

function expression/declaration, new Function -- the constructor should all be Function

function FF(){} FF.constructor === Function; // true (Function()).constructor === Function; // true. (new Function()).constructor === Function; // true.

The Object instance that is created in [[construct]] could have the constructor property as DontEnum. This seems to be a compatibility issue with ES3.

In ES3, you can't depend on the enumerability of an object's own constructor property. This is because prototype objects have a constructor property that is flagged DontEnum.

The idea is to make constructor a DontEnum property on all objects.

(not just ones that were created through [[construct]] to be used as prototype properties).

constructor would be a default value given to the object in [[construct]]

What do you think?

# Brendan Eich (18 years ago)

On Sep 23, 2007, at 12:22 PM, Garrett Smith wrote:

in no case is the value of (new function(){}).constructor Function.

It shouldn't be, but it is in OSX Ref Impl. (I did not build this).

js> (new function(){}).constructor [function Function]

No, that's just bugs.ecmascript.org/ticket/64 -- proof:

(new function(){}).constructor [function Function]

(new function(){}).constructor === Function

false

f = function(){} [function Function]

(new f).constructor === f

true

With Function.prototype.toString buggy, you need to test identity of
function objects.

# Garrett Smith (18 years ago)

On 9/23/07, Brendan Eich <brendan at mozilla.org> wrote:

On Sep 23, 2007, at 12:22 PM, Garrett Smith wrote:

in no case is the value of (new function(){}).constructor Function.

It shouldn't be, but it is in OSX Ref Impl. (I did not build this).

js> (new function(){}).constructor [function Function]

No, that's just bugs.ecmascript.org/ticket/64 -- proof:

(new function(){}).constructor [function Function]

(new function(){}).constructor === Function false

f = function(){} [function Function]

(new f).constructor === f true

Ah, OK.

js> Function().toSource()

function(){}

Works.

I usually like modifying toString anyway.

F = function(){}; F.prototype = { toString : function() { return "Fork!"; } }; f = new F; f.toString() //f.constructor

With Function.prototype.toString buggy, you need to test identity of function objects.

Buggy or not, since functions could have different [[Scope]], testing toString makes no sense.

Testing toSource is useful for seeing if it's a native function (eval, or RegExp test), but Function.prototype.toSource() isn't provided in the spec and isn't supported in JScript.

Garrett

# P T Withington (18 years ago)

On 2007-09-23, at 14:14 EDT, Brendan Eich wrote:

But for ES3 and real web compatibility, I don't think changing the algorithm to not allow ordinary ES3 functions used as constructors to return objects other than the one set up by [[Construct]] will work.

Right, this will break the web. Tucker can weigh in on the workarounds OpenLaszlo needed to cope with the instance of this bug in Flash (AS2, and I think AS3 still, do not let a function return a different object from the one passed in as this when called via new).

The particular case that bit us was trying to create a portable
'inherited hash' (a constructor to create an object with another
object as its [[proto]]. We wanted to write a constructor:

function InheritedHash(from) { if (from) { function xtor() {}; xtor.prototype = from; return new xtor(); } return this; }

We originally worked around this by rewriting all new calls in our
compiler to be function calls instead. Since this was the only case
where we needed to be able to return an alternate object from a
constructor, we eventually just replaced it with a factory and
replaced all calls.

[InheritedHash may or may not be a good idea. The original concept
was that it was more efficient than copying all the values into a new
hash -- sharing of values was not actually a requirement.]

# P T Withington (18 years ago)

On 2007-09-23, at 14:14 EDT, Brendan Eich wrote:

On Sep 23, 2007, at 8:59 AM, liorean wrote:

  1. The constructor property should be on the object instance created by the function.

That argument I agree with. It should be on the instance and not the prototype.

The reason for the original prototype-owned constructor was to afford a back-pointer from prototype to constructor function without imposing a per-instance property (which could be optimized to be shared where possible, overridden where desired -- but at some cost in implementation complexity).

I'm not convinced it's worth changing this for ES4. Anyway it is very late to have a new proposal -- we are finalizing proposals next week at the face-to-face meeting.

FWIW, to emulate classes in our runtime, our constructors always
create a constructor property in the instances they create (pointing
to the constructor) so the class of an instance is given by its
constructor property, and the superclass of a class is its
prototype.constructor property. For that reason, I would be in favor
of this proposal (to make constructor a non-enumerable property of
instance).

# P T Withington (18 years ago)

On 2007-09-23, at 14:14 EDT, Brendan Eich wrote:

On Sep 23, 2007, at 8:59 AM, liorean wrote:

  1. The constructor property should be on the object instance created by the function.

That argument I agree with. It should be on the instance and not the prototype.

The reason for the original prototype-owned constructor was to afford a back-pointer from prototype to constructor function without imposing a per-instance property (which could be optimized to be shared where possible, overridden where desired -- but at some cost in implementation complexity).

I'm not convinced it's worth changing this for ES4. Anyway it is very late to have a new proposal -- we are finalizing proposals next week at the face-to-face meeting.

So, was nothing done about this? We're starting to work on an es4
back-end for our stuff and running into this issue. We can make sure
all our constructors give each instance a constructor slot (and we can
smash the class prototype.constructor to point to the superclass) as
we do for our es3 back end; but I was really hoping for a cleaner
solution in es4.

Is there some other way in es4 that from an instance one can navigate
up the superclass chain? Can I say:

super.constructor

perhaps, to find my class's superclass?

# Brendan Eich (18 years ago)

On Dec 14, 2007, at 12:50 PM, P T Withington wrote:

On 2007-09-23, at 14:14 EDT, Brendan Eich wrote:

The reason for the original prototype-owned constructor was to afford a back-pointer from prototype to constructor function without imposing a per-instance property (which could be optimized to be shared where possible, overridden where desired -- but at some cost in implementation complexity).

I'm not convinced it's worth changing this for ES4. Anyway it is very late to have a new proposal -- we are finalizing proposals next week at the face-to-face meeting.

So, was nothing done about this? We're starting to work on an es4 back-end for our stuff and running into this issue. We can make sure all our constructors give each instance a constructor slot (and we can smash the class prototype.constructor to point to the superclass) as we do for our es3 back end; but I was really hoping for a cleaner solution in es4.

Nothing's changed, no proposal that avoids per-instance overhead or
more complicated implementation strategies to avoid that. There's
also an entrainment hazard, not huge but non-zero risk of introducing
leaks into existing web apps if we entrain the constructor where the
web app code intentionally clears prototype.constructor (which is
read/write).

The constructor property is and always was intended to be a property
of the prototype, not of each instance. Changing that now is hard.
The merits are not compelling enough IMHO.

Is there some other way in es4 that from an instance one can navigate up the superclass chain? Can I say:

super.constructor

perhaps, to find my class's superclass?

For a class C, C.prototype.constructor is indeed C. But super does
not work that way -- it's used for invoking the super-class
constructor, rather:

class B { var x;function B(x) : x=x {} } new B(2).x

2

class D extends B { var y; function D(x,y) : y=y, super(x) {} } d = new D(3,4) [object D]

d.x

3

d.y

4

To reflect on inheritance and other relations, use the meta-objects
interfaces:

proposals:meta_objects

Given class C:

let Ctype = reflect::typeOf(C); for (let Csup in Ctype.superTypes()) { // Csup is a base class or interface of C here }