archives

« Bugzilla Issues Index

#2863 — 23.1.1 The Map Constructor, re: calling without new?


In this section, there is the following text:

"When Map is called as a function rather than as a constructor, it initializes its this value with the internal state necessary to support the Map.prototype built-in methods."


Is this referring to:

var m = Map();

Or

Map.call(this);

Or both?



Additionally, I cannot find the specification for the consensus that was reached re: calling the new built-in constructors without new: https://github.com/rwaldron/tc39-notes/blob/master/es6/2013-07/july-25.md#consensusresolution-6


This applies to Set as well


(In reply to comment #0)

>
> Is this referring to:
>
> var m = Map();
>
> Or
>
> Map.call(this);
>
> Or both?
>

Both, and perhaps most importantly:

class MyMap extends ap {
constructor(...args) {super(...args)}
}

With the ES6 refactoring of the new operator into separate @@create and constructor call, the primary responsibility of a constructor function is not the creation of new instances but rather the initialization of new instances.

>
> Additionally, I cannot find the specification for the consensus that was
> reached re: calling the new built-in constructors without new:
> https://github.com/rwaldron/tc39-notes/blob/master/es6/2013-07/july-25.md#consensusresolution-6

It's what's in the ES6 spec. For Map, it's lines 2-4 of 23.1.1.1. The recorded consensus was just ratifying what was already in the spec.

The motivation is that it's really hard (particularly in pure JS code) to write a constructor function that works correctly as both a factory function (called without new) and as an instance initializer (particularly when super called). It's cleaner and simpler to not have the factory behavior for constructor functions and to have them act only as instance initializers. In ES6 the only built-in constructors that work as both factories and initializers are those where this is a legacy compatability requirement.


> For Map, it's lines 2-4 of 23.1.1.1.

But aren't those conditions satisfied? Or am I misunderstanding the outcome of this:

"When Map is called as a function rather than as a constructor, it initializes its this value with the internal state necessary to support the Map.prototype built-in methods."

More specifically, does "initializes its this value with the internal state necessary to support the Map.prototype built-in methods" result in the `this` value being an object with a [[MapData]] internal slot that is initially `undefined`?


I recall the motivation, as I was in support of this change prior to the f2f and the recorded notes—this was a conversation Erik and I had several months in advance of the meeting.


(In reply to comment #3)
> > For Map, it's lines 2-4 of 23.1.1.1.
>
> But aren't those conditions satisfied? Or am I misunderstanding the outcome of
> this:
>
> "When Map is called as a function rather than as a constructor, it initializes
> its this value with the internal state necessary to support the Map.prototype
> built-in methods."
>
> More specifically, does "initializes its this value with the internal state
> necessary to support the Map.prototype built-in methods" result in the `this`
> value being an object with a [[MapData]] internal slot that is initially
> `undefined`?

The way to think about this is that @@create creates a new object instance with the internal slots ([[MapData]]). The constructor then validates that the object has those internal slots.

>
>
> I recall the motivation, as I was in support of this change prior to the f2f
> and the recorded notes—this was a conversation Erik and I had several months in
> advance of the meeting.


(In reply to comment #3)
> > For Map, it's lines 2-4 of 23.1.1.1.
>
> But aren't those conditions satisfied? Or am I misunderstanding the outcome of
> this:
>
> "When Map is called as a function rather than as a constructor, it initializes
> its this value with the internal state necessary to support the Map.prototype
> built-in methods."

Actually, there is nothing normative about the above paragraph, at all. It's just a a very vague description of what the algorithm actually does.

Such text has been a general problem for the spec. because some people find it useful, but don't realize that it is generally non-normative. In this case, it might be clearer if it said "it attempts to initialize".

In general, this is boilerplate that is used for all constructors. If I find the time I'll think about how I it could be made clearer.

>
> More specifically, does "initializes its this value with the internal state
> necessary to support the Map.prototype built-in methods" result in the `this`
> value being an object with a [[MapData]] internal slot that is initially
> `undefined`?
>
If the this object wasn't instantiated (by @@create) with a [[MapData]] then attempting to initialize it will throw.


(In reply to comment #5)
> (In reply to comment #3)
> > > For Map, it's lines 2-4 of 23.1.1.1.
> >
> > But aren't those conditions satisfied? Or am I misunderstanding the outcome of
> > this:
> >
> > "When Map is called as a function rather than as a constructor, it initializes
> > its this value with the internal state necessary to support the Map.prototype
> > built-in methods."
>
> Actually, there is nothing normative about the above paragraph, at all. It's
> just a a very vague description of what the algorithm actually does.
>
> Such text has been a general problem for the spec. because some people find it
> useful, but don't realize that it is generally non-normative. In this case, it
> might be clearer if it said "it attempts to initialize".
>
> In general, this is boilerplate that is used for all constructors. If I find
> the time I'll think about how I it could be made clearer.

Ok, that's actually really helpful to know.

>
> >
> > More specifically, does "initializes its this value with the internal state
> > necessary to support the Map.prototype built-in methods" result in the `this`
> > value being an object with a [[MapData]] internal slot that is initially
> > `undefined`?
> >
> If the this object wasn't instantiated (by @@create) with a [[MapData]] then
> attempting to initialize it will throw.

Thank you, this answers my question.