A new ES6 draft is available

# Allen Wirfs-Brock (11 years ago)

This is Rev 19, The Sept. 27 Draft harmony:specification_drafts#september_27_2013_draft_rev_19 And the HTML is available at people.mozilla.org/~jorendorff/es6-draft.html

Changes include:

  • Better internal cross-linking
  • Restored NoIn expression productions
  • Added NoIn productions for Arrow functions
  • Made yield a reserved word
  • Corrected TypedArray constructor 22.2.4.1
  • Changed branding for DataView to make them more polymorphic with Typed Arrays WRT buffer access and ArrayBuffer.isVGiew
  • Fixed Array.prototype.concat, filter,map, slice, splice result object construction.
  • Changed Array.prototype.concat, filter,map, slice, splice such so that when result object is an Array instance, it is from the same Realm as the method.
  • Clarified differences between %TypedArray% prototype methods and corresponding Array prototype
  • Renamed [[GetInheritance]] to [[GetPrototypeOf]] and [[SetInheritance]] to [[SetPrototypeOf]].
  • Changed Proxy [[GetPrototypeOf]] invariant so it only applies if target is not extensible.
  • Updated CreateOwnDataProperty to to eliminate the assert that the property doesn’t exist. Callers may need to check for success.
  • Fixed bug in creating result array for %TypedArray% filter
  • Added algorithms for Object.assign and Object.mixin
  • Added a IteratorStep abstract operation to simply most internal uses of iterators
  • Removed the recently added requirement that Typed Array instances must be non=extensible
  • renamed @@ToPrimitive as @@toPrimitive
  • Updated Object.prototype.toString for symbols, Math, and JSON
  • Added @@toStringTag methods for Math and JSON
  • Made Symbol a primitive type with a wrapper object named Symbol
  • Make new Object(Symbol()) throw a TypeError
  • Added properties of Symbol containing the well known symbols
  • Eliminated destructuring throw for non-existant source properties without a corresponding initializer
  • Renamed Math roundFloat32 → Math.fround
  • Math.hypoth is now viadic
  • Normalized <CR><LF> and <CR> to <LF> in template strings.
  • Eliminated [[HasOwnProperty]] MOP operation
  • Must say new DataView(...) to create a new one
  • Resolved bugs: 1940-1939, 1937-1930, 1928-1911, 1907-1904, 1899, 1896-1894, 1891, 1889, 1884-1881, 1878-1871, 1867, 1864, 1862-1860, 1857-1856, 1853, 1850-1816, 1812-1810, 1808-1806, 1803, 1606, 1598, 1589, 1153
# Andreas Rossberg (11 years ago)

On 28 September 2013 00:05, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

This is Rev 19, The Sept. 27 Draft harmony:specification_drafts#september_27_2013_draft_rev_19 And the HTML is available at people.mozilla.org/~jorendorff/es6-draft.html

Changes include: [...]

Made Symbol a primitive type with a wrapper object named Symbol Make new Object(Symbol()) throw a TypeError

I can't remember any discussion about Object(Symbol()). Why should it be disallowed?

On the other hand, we agreed the other week on making 'new Symbol' and Symbol.prototype.toString throw. That should address all likely accidents.

# Domenic Denicola (11 years ago)

From: es-discuss [mailto:es-discuss-bounces at mozilla.org] On Behalf Of

I can't remember any discussion about Object(Symbol()). Why should it be disallowed?

On the other hand, we agreed the other week on making 'new Symbol' and Symbol.prototype.toString throw. That should address all likely accidents.

I only remember Dave briefly mentioning it as one of the potential ways to get a wrapper object; I don't remember a decision to prohibit it.

On the other hand, this is somewhat attractive, as it prevents getting a symbol wrapper object except inside sloppy-mode methods/accessors added to Symbol.prototype, wherein this is a wrapper. Which means, unless I missed a case, that in strict mode it is impossible to create a symbol wrapper object.

# Andreas Rossberg (11 years ago)

On 30 September 2013 13:41, Domenic Denicola <domenic at domenicdenicola.com> wrote:

I only remember Dave briefly mentioning it as one of the potential ways to get a wrapper object; I don't remember a decision to prohibit it.

On the other hand, this is somewhat attractive, as it prevents getting a symbol wrapper object except inside sloppy-mode methods/accessors added to Symbol.prototype, wherein this is a wrapper. Which means, unless I missed a case, that in strict mode it is impossible to create a symbol wrapper object.

Yes, but there seems nothing inherently risky or error-prone in (purposefully and explicitly) creating a wrapper object. And since you can do it for other primitive types, I think the scales weigh towards consistency on this one.

# Allen Wirfs-Brock (11 years ago)

On Sep 30, 2013, at 4:53 AM, Andreas Rossberg wrote:

Yes, but there seems nothing inherently risky or error-prone in (purposefully and explicitly) creating a wrapper object. And since you can do it for other primitive types, I think the scales weigh towards consistency on this one.

At this point, we should probably discuss what is actually in the spec. draft rather than the change summary or the meeting notes.

The lastest draft throws when doing an implicitly ToString conversion 1 of a Symbol primitive value. This means that (aSymbol + "suffix") or ("prefix" + aSymbol) 2 will throw, which was the case that I believe people were most concerned about.

ToNumber conversion of a Symbol value is currently specified 3 as producing a NaN for implicit numeric conversions of Symbols resulting in NaN values that will propagate through numeric computations. We could make ToNumber throw for Symbol values but NaN seems more consistent with the ES handling of invalid numeric conversions.

ToBoolean of a String value is defined3 to return true. This seems consistent with the rest of ES, although it would be easy enough to define this conversion to throw.

This isn't current in the spec, but we should probably also make implicit string or number conversions of Symbol wrappers throw. We can to this simply by defining a @@ToPrimitive method 4 on Symbol.prototype that throws .

Because, all of the appropriate implicit conversions produce error results, I didn't see any real reason why an explicit call to String.prototype.toString should throw. This certainly seems like a reasonable way for a program to explicitly convert a Symbol value to a string value for debugging, logging, or other proposes. This method is currently defined 5 to produce a string of the form "Symbol(<descriptive string provided when created>)". (modulo a small spec. bug)

As discussed at the meeting, (new Symbol) will throw. This is accomplished by making Symbol's @@create method 6 throw.

Object(aSymbol) is currently spec'ed to return a wrapper for the Symbol via a call to ToObject 7. While idea of throwing was mentioned at the meeting, I'm not sure why it should be special cased to throw. This is how a programmer would generically convert primitive values to objects in situations where this is necessary. For example,

 "toString" in Object(expr)

Note that a call to ToObject is also how the implicit conversions used to deference Reference values with primitive value bases (eg, aSymbol.foo) works.

I'm not sure why my change log says (new Object(Symbol())) throws because that isn't actually in the draft 9. Perhaps I was about to make that change, based upon the meeting minutes, and got interrupted or something. Regardless, it does need to do something. The most consistent thing would be to treat it, like all other primitive values, as a request to create a Symbol wrapper object.

Allen

# Brandon Benvie (11 years ago)

On 9/30/2013 4:41 AM, Domenic Denicola wrote:

I can't remember any discussion about Object(Symbol()). Why should it be disallowed?

On the other hand, we agreed the other week on making 'new Symbol' and Symbol.prototype.toString throw. That should address all likely accidents. I only remember Dave briefly mentioning it as one of the potential ways to get a wrapper object; I don't remember a decision to prohibit it.

On the other hand, this is somewhat attractive, as it prevents getting a symbol wrapper object except inside sloppy-mode methods/accessors added to Symbol.prototype, wherein this is a wrapper. Which means, unless I missed a case, that in strict mode it is impossible to create a symbol wrapper object.

Calling Object as a function is currently infallible and I've seen plenty of code that makes this assumption. This should probably not be changed.

# Brendan Eich (11 years ago)

You shoot, you score.

This is decisive -- cc'ing Allen.

# Allen Wirfs-Brock (11 years ago)

On Sep 30, 2013, at 1:14 PM, Brendan Eich wrote:

You shoot, you score.

This is decisive -- cc'ing Allen.

Already spec'ed to do the wrapping. See my previous message on this thread.

# Andreas Rossberg (11 years ago)

On 30 September 2013 18:20, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

The lastest draft throws when doing an implicitly ToString conversion [1] of a Symbol primitive value. This means that (aSymbol + "suffix") or ("prefix" + aSymbol) [2] will throw, which was the case that I believe people were most concerned about.

ToNumber conversion of a Symbol value is currently specified [3] as producing a NaN for implicit numeric conversions of Symbols resulting in NaN values that will propagate through numeric computations. We could make ToNumber throw for Symbol values but NaN seems more consistent with the ES handling of invalid numeric conversions.

ToBoolean of a String value is defined[3] to return true. This seems consistent with the rest of ES, although it would be easy enough to define this conversion to throw.

This isn't current in the spec, but we should probably also make implicit string or number conversions of Symbol wrappers throw. We can to this simply by defining a @@ToPrimitive method [4] on Symbol.prototype that throws .

OK, thanks for the summary, that makes sense. The one worry I have, though, is that not tainting S.p.toString itself will miss cases where code tries to convert some value x to a property name by explicitly calling x.toString(). Currently, that works for everything but null and undefined, so I assume that this pattern is used quite a bit.

Because, all of the appropriate implicit conversions produce error results, I didn't see any real reason why an explicit call to String.prototype.toString should throw. This certainly seems like a reasonable way for a program to explicitly convert a Symbol value to a string value for debugging, logging, or other proposes. This method is currently defined [5] to produce a string of the form "Symbol(<descriptive string provided when created>)". (modulo a small spec. bug)

There always is the generic Object.prototype.toString that can be made to handle symbols. That is what V8 currently does (producing a string just like you describe above).

# Allen Wirfs-Brock (11 years ago)

On Oct 1, 2013, at 3:10 AM, Andreas Rossberg wrote:

OK, thanks for the summary, that makes sense. The one worry I have, though, is that not tainting S.p.toString itself will miss cases where code tries to convert some value x to a property name by explicitly calling x.toString(). Currently, that works for everything but null and undefined, so I assume that this pattern is used quite a bit.

Do you think thing it really is? Any value (other than null and undefined) automatically converts to a string when used as a property selector. so there really isn't any reason (other than lack of knowledge) for someone to explicitly toString values before using them as a property key. On the other hand, there are plenty of reasons in other use cases where someone might explicitly toString because they actually want a string description of a value.

Either choice we make here is probably going to trip up some code. I think what I've specified is the best set of trade-offs, but I willing to be convinced otherwise. I suspect hard evidence supporting either alternative is hard to find

There always is the generic Object.prototype.toString that can be made to handle symbols. That is what V8 currently does (producing a string just like you describe above).

But this forces such code to be rewritten to special case Symbol values (assuming that they don't want, for example, string values and Arrays to display as [object. String] and [object Array]). Also, the spec. current says that O.P.toString for a Symbol returns [object Symbol] rather than Symbol(<descriptive string provided when created>). This is to keep it consistent with other types of values and code that expects O.p.toString to always produce the [object <name>] pattern.

# Brendan Eich (11 years ago)

Allen Wirfs-Brock wrote:

Currently, that works for everything but null and undefined, so I assume that this pattern is used quite a bit.

Do you think it really is?

I don't. (That is, I don't see much x.toString() feeding into bracketed property lookup, if any.)

Explicit .toString() calling is rare because verbose, in addition to throwing on null and undefined. People use + ''. But that's covered, and I say if someone has a symbol named x (whether they know it's a symbol or "any") and they call .toString(), they should get what they're asking for: throw on null or undefined (or a misbehaving impl), otherwise a string.

# Claude Pache (11 years ago)

Le 1 oct. 2013 à 19:33, Brendan Eich <brendan at mozilla.com> a écrit :

Allen Wirfs-Brock wrote:

Currently, that works for everything but null

and undefined, so I assume that this pattern is used quite a bit.

Do you think it really is?

I don't. (That is, I don't see much x.toString() feeding into bracketed property lookup, if any.)

Explicit .toString() calling is rare because verbose, in addition to throwing on null and undefined. People use + ''.

I tend to use String(x) (which is equivalent).

But that's covered, and I say if someone has a symbol named x (whether they know it's a symbol or "any") and they call .toString(), they should get what they're asking for: throw on null or undefined (or a misbehaving impl), otherwise a string.

A bit annoying that ad-hoc debugging code like alert("got argument: " + x) or alert("got argument: " + String(x)) will throw for Symbols, while alert("got argument: " + x.toString()) will throw for null and undefined, and (usually) for Object.create(null).

# Allen Wirfs-Brock (11 years ago)

On Oct 1, 2013, at 1:22 PM, Claude Pache wrote:

Le 1 oct. 2013 à 19:33, Brendan Eich <brendan at mozilla.com> a écrit :

Allen Wirfs-Brock wrote:

Currently, that works for everything but null

and undefined, so I assume that this pattern is used quite a bit.

Do you think it really is?

I don't. (That is, I don't see much x.toString() feeding into bracketed property lookup, if any.)

Explicit .toString() calling is rare because verbose, in addition to throwing on null and undefined. People use + ''.

I tend to use String(x) (which is equivalent).

Actually it isn't. String(x) is specified to call the ToString abstract operation on x which in the current spec./proposal will throw if x is a Symbol value.

But that's covered, and I say if someone has a symbol named x (whether they know it's a symbol or "any") and they call .toString(), they should get what they're asking for: throw on null or undefined (or a misbehaving impl), otherwise a string.

A bit annoying that ad-hoc debugging code like alert("got argument: " + x) or alert("got argument: " + String(x)) will throw for Symbols, while alert("got argument: " + x.toString()) will throw for null and undefined, and (usually) for Object.create(null).

I suppose we could special case String(x) when x is a Symbols

# Claude Pache (11 years ago)

Explicit .toString() calling is rare because verbose, in addition to throwing on null and undefined. People use + ''.

I tend to use String(x) (which is equivalent).

Actually it isn't. String(x) is specified to call the ToString abstract operation on x which in the current spec./proposal will throw if x is a Symbol value.

Sorry for for the ambiguity, I meant: equivalent to + ''.

# Allen Wirfs-Brock (9 years ago)

Rev31 (January 15, 2015) of the ECMAScript 2015 Language Specification is ready for review at harmony:specification_drafts#january_15_2015_draft_rev_31

Changes include: Updated specification to use and support the new built-in subclassing scheme described at: tc39/ecma262/blob/master/workingdocs/ES6-super-construct%3Dproposal.md

  • Added newTarget parameter to [[Construct]], Reflect.construct, and proxy ‘construct’ trap.
  • Added NewTarget binding to Function Environment Records and abstract operations/methods of setting and accessing that binding
  • Redefined [[Construct]] for ordinary ECMAScript functions so “derived” constructors don’t preallocate the new object and bind this.
  • Changed [[Construct]] for ordinary ECMAScript functions so “derived” constructors will throw if they try to explicitly return a non-object.
  • Within constructors this binding has TDZ access semantics.
  • super(...) syntactic form now illegal in Function/GeneratorDeclaration/Expression
  • super(...) and new super(...) propagates current NewTarget to [[Construct]] call
  • super(...) binds this value upon return from [[Construct]] call, throw if new already bound
  • Refactored [[Call]] and [[Construct]] for ordinary ECMAScript functions so they can continue to shared common spec steps.
  • Updated Generator object instantiation to work with new [[Construct]] design
  • Refactored Function constructor and GeneratorFunction to share a common abstract operation based definition
  • Every built-in constructor changed to merge object allocation and initialization code. In some cases (eg, TypedArray and Promise) significant refactoring of allocation and initialization logic.
  • Updated [[Construct]] of Bound functions to handle newTarget parameter.
  • Several of the above items are tentative because they still lack full TC39 discussion and review. The following are particularly tentative:
    • restrictions on where super(...) is allowed may change
    • new supper(...) might go away or change
    • Support for the new.target access syntax (yellow highlight in spec text) is speculative and may move to ES7 and/or change

Other changes

  • Merged AllocArrayBuffer and SetArrayBufferData into single abstract operation
  • %TypedArray%.of now requires that its this value is a valid Typed Array constructor
  • Replaced “moduleId” with “sourceCodeId” and eliminated most usage of such ids in module related abstract operations
  • Some tweaking of Language Overview in 4.2
  • A new document title
  • Resolved bugs: 3543-3527, 3524-3523, 3520, 3517-3516, 3514-3511, 3501-3496, 3494-3479, 3310, 3229, 3136, 2865, 2536, 2495, 2179
# Kevin Smith (9 years ago)

Changes include: Updated specification to use and support the new built-in subclassing scheme described at: tc39/ecma262/blob/master/workingdocs/ES6-super-construct%3Dproposal.md

This looks nice. An interesting question:

For classes that have divergent [[Construct]]/[[Call]] behavior, should the [[Call]] behavior be "inherited" by derived classes?

class MyDate extends Date {}
console.log(MyDate(1, 2, 3));  A string, or throw an error?
# Allen Wirfs-Brock (9 years ago)

Since the above class definition does not include an explicit constructor body, it gets the equivalent of

constructor(...args) {super(...args)}

as its implicit constructor definition

A 'super()' call throws if the NewTarget is null (ie, if the constructor is invoked via [[Call]] )

If you want to inherit call behavior you need to code it as:

class MyDate extends Date {
    constructor(...args) {
        if (new.target===null) return super.constructor(...args)
        super(...args);
    }
}

That's assuming 'new.target' makes it into ES6. Without it you would have to do something like:

class MyDate extends Date {
    constructor(...args) {
        let calledAsFunction=true;
        try {
            let thisValue = this;  //can't reference 'this' prior to 'super()' in a [[Construct]] call of a derived function
        } catch (e} {
            let calledAsFunction = false
        }
        if (calledAsFunction) return super.constructor(...args)
        super(...args);
    }
}
# Allen Wirfs-Brock (9 years ago)

err,

try {
    let thisValue = this;  //can't reference 'this' prior to 'super()' in a [[Construct]] call of a derived function
} catch (e} {
    calledAsFunction = false  //no let here
}
# Brendan Eich (9 years ago)

Gotta agree new.target is nicer to read and write!

# Frankie Bagnardi (9 years ago)

I'm also expecting a lot of questions about 'what is this new.target thing in this code?', 'is new a variable?', 'where does it come from?', 'isn't new an operator?', etc.

if (this instanceof MyDate) ...

... is clearer, but I guess it needs to be disallowed because of the other rules.

# Allen Wirfs-Brock (9 years ago)

On Jan 17, 2015, at 5:59 AM, Frankie Bagnardi wrote:

I'm also expecting a lot of questions about 'what is this new.target thing in this code?', 'is new a variable?', 'where does it come from?', 'isn't new an operator?', etc.

as proposed, new.target is a MemberExpression consisting of the three token sequence new . target

It is only allowed in function code.

If the enclosing function is invoked as a call expression the value of new.target is null

(function() {assert(new.target===null)})()

if the enclosing function is directly invoked as a constructor via new the value of new.target is the function

function f() {assert(new.target===f)}
new f();

if the enclosing function is indirectly invoked as a constructor via super() or new super() the value of new.target is the function new was directly applied to

class Super  { constructor() {assert(new.target===Sub)}}
class Sub extends Super {constructor() {super()}}
new Sub();

if (this instanceof MyDate) ...

... is clearer, but I guess it needs to be disallowed because of the other rules.

When a function is called (rather than new'ed) its this value is usually undefined (assuming a strict function)

# Claude Pache (9 years ago)

Le 17 janv. 2015 à 14:59, Frankie Bagnardi <f.bagnardi at gmail.com> a écrit :

I'm also expecting a lot of questions about 'what is this new.target thing in this code?', 'is new a variable?', 'where does it come from?', 'isn't new an operator?', etc.

if (this instanceof MyDate) ...

... is clearer, but I guess it needs to be disallowed because of the other rules.

I don't find the this instanceof MyDate test clearer, but it may appear so because it is idiomatic. In fact, it is a somewhat indirect way to test what you want. (And it may be incorrect in some cases, which is a danger when you use indirect paths.)

# Domenic Denicola (9 years ago)

On Jan 17, 2015, at 12:31, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

If the enclosing function is invoked as a call expression the value of new.target is null

Just curious, why null instead of undefined?

# Brendan Eich (9 years ago)

Frankie Bagnardi wrote:

I'm also expecting a lot of questions about 'what is this new.target thing in this code?', 'is new a variable?', 'where does it come from?', 'isn't new an operator?', etc.

if (this instanceof MyDate) ...

... is clearer, but I guess it needs to be disallowed because of the other rules.

It doesn't mean the same thing as new.target, of course. Also, new.target is not useful only as a predicate -- it is the original constructor that was new'ed.

# Allen Wirfs-Brock (9 years ago)

On Jan 17, 2015, at 9:53 AM, Domenic Denicola wrote:

Just curious, why null instead of undefined?

null is used to indicate no [[Prototype]], so it seem to me to be a better match for this situation.

If practice, I suspect that a truthy test will usually be applied, so it doesn't make much difference.

# Fabrício Matté (9 years ago)

I agree with Frankie. Assume a developer who has never seen this new.target construct before. They will first think that this is an invalid expression, as new is an operator. Then, upon seeing this code execute, the natural question is "What is new? Is it an identifier injected into Environment Records created by [[Call]] and [[Construct]]? Does this identifier resolve to an object (so that the MemberExpression would make sense)?"]

# Brendan Eich (9 years ago)

Fabrício Matté wrote:

I agree with Frankie. Assume a developer who has never seen this new.target construct before.

In general, ES6 has new syntax, so this is a "learn it and use it" bump, one of many.

They will first think that this is an invalid expression, as new is an operator. Then, upon seeing this code execute, the natural question is "What is new? Is it an identifier injected into Environment Records created by [[Call]] and [[Construct]]? Does this identifier resolve to an object (so that the MemberExpression would make sense)?"]

new.target in the proposal (which does not yet have consensus) evaluates to an object, but (new) is a syntax error as in ES1-5.

Yeah, it's a bit odd to grab new.identifier syntax-space and start by defining only new.target. Alternatives welcome. new^ already got an anti-grawlix reaction, new? did too (perhaps less but still).

# Fabrício Matté (9 years ago)

For a short term solution, I would suggest arguments.new.target. The arguments object already contains info about how the function was called (its arguments, the deprecated/obsolete callee and obsolete/never-spec'd caller properties), so adding information about how the function was called (whether it was new'ed) to arguments would make sense imo.

For the long term, I'd like to see a new identifier injected into function scopes which exposes the Lexical Environment/Environment Record internals. Then we can use __scope__.new.target or Reflect.isNewed(__scope__) (or isConstructed, which may make more sense seeing as there will be Reflect.construct). Of course, this __scope__ binding should only be injected in the Environment Record if the binding does not exist yet after registering the function body's declarations, for back-compat reasons. And obviously, __scope is just a placeholder name for this suggestion, I don't really mind how it will be called.

# Allen Wirfs-Brock (9 years ago)

On Jan 17, 2015, at 10:50 AM, Brendan Eich wrote:

Fabrício Matté wrote:

I agree with Frankie. Assume a developer who has never seen this new.target construct before.

In general, ES6 has new syntax, so this is a "learn it and use it" bump, one of many.

A general challenge in extending JS is that we can't add new reserved words, so adding new meaning to existing reserved keywords in one way around that limitation.

Currently in ES6, the only reserved keywords that can appear immediately before a . are this and super. Any other reserved word followed by a . is a syntax error. So reserved words followed by period and an identifier is one of the few available extension alternatives we have available. And is a natural ready syntax think of new.target' as meaning give me the target value of the currently active new operator.

They will first think that this is an invalid expression, as new is an operator. Then, upon seeing this code execute, the natural question is "What is new?

hopefully they will say what is `new.target', "google it" and immediately find the answer.

Is it an identifier injected into Environment Records created by [[Call]] and [[Construct]]? Does this identifier resolve to an object (so that the MemberExpression would make sense)?"]

I suspect the hypothetical naive JS programmer postulated above wound't be aware of any of those concepts. That's why I explained in down thread without using them.

new.target in the proposal (which does not yet have consensus) evaluates to an object, but (new) is a syntax error as in ES1-5.

Yeah, it's a bit odd to grab new.identifier syntax-space and start by defining only new.target. Alternatives welcome. new^ already got an anti-grawlix reaction, new? did too (perhaps less but still).

Once this idea is in play, It also seems like a good solution for some other extensions we have grapple with. Consider, for example:

function.callee
function.arguments
module.name

etc.

This should be an interesting area of exploration for ES7 and beyond

# Kevin Smith (9 years ago)

Once this idea is in play, It also seems like a good solution for some other extensions we have grapple with. Consider, for example:

function.callee
function.arguments
module.name

or yield.input

# Frankie Bagnardi (9 years ago)

arguments.new.target makes more sense to me.

If we do want to move towards keyword.identifier being a normal occurance, then I think new.target is perfectly reasonable. I'm all for that, and it makes the job of tooling a lot simpler where it's used.

In the current draft, is new["target"] a syntax error, or equivalent to new.target?

# Allen Wirfs-Brock (9 years ago)

On Jan 17, 2015, at 11:37 AM, Frankie Bagnardi wrote:

arguments.new.target makes more sense to me.

the problem with this or hanging anything off of arguments is that it can be a potential accidental capability leak if people pass arguments around thinking they are just passing an array of values. That's why ES5 removed arguments.callee from strict mode.

If we do want to move towards keyword.identifier being a normal occurance, then I think new.target is perfectly reasonable. I'm all for that, and it makes the job of tooling a lot simpler where it's used.

In the current draft, is new["target"] a syntax error, or equivalent to new.target?

syntax error! new.target is a special form and not a property access. We probably don't want to allow make it seem more like a property access by allowing a [ ] formulation.

# Fabrício Matté (9 years ago)

Currently in ES6, the only reserved keywords that can appear immediately before a . are this and super.

The this binding resolves to a value, so MemberExpressions make sense. The super keyword is being implemented in ES6, so there are no precedents to set expectations.

Any other reserved word followed by a . is a syntax error. So reserved

words followed by period and an identifier is one of the few available extension alternatives we have available. And is a natural ready syntax think of new.target' as meaning give me the target value of the currently active new operator.

I agree new.target is very natural and pleasant to read. It just feels rather alien to see an operator in the beginning of a MemberExpression, which currently would only be allowed in this very specific scenario. Of course, if this syntax extension form would be useful for other use cases as Kevin and you have outlined, then I don't oppose it.

I suspect the hypothetical naive JS programmer postulated above wound't be aware of any of those concepts.

A naive one probably not, but a curious avid developer most definitely would. ;)

hopefully they will say what is `new.target', "google it" and immediately find the answer.

You mean, land on a Stack Overflow answer with thousands of upvotes and very little explanation about why/how a MemberExpression can begin with an operator. Of course, if you interpret new as simply a ReservedWord token instead of an operator, then everything makes perfect sense.

# Allen Wirfs-Brock (9 years ago)

On Jan 17, 2015, at 11:57 AM, Fabrício Matté wrote:

You mean, land on a Stack Overflow answer with thousands of upvotes and very little explanation about why/how a MemberExpression can begin with an operator. Of course, if you interpret new as simply a ReservedWord token instead of an operator, then everything makes perfect sense.

The way I accomplish in the grammar was to add the productions:

MemberExpression : 
      MetaProperty
MetaProperty :
       'new'    '.'   'target'

So we could start talking about "meta properties" as a MemberExpression alternative and say new.target is a "meta property".

# Fabrício Matté (9 years ago)

Oh thanks! I just got a copy of the draft rev 31 to check it out.

"Meta properties" sounds like a good name to me. Also, "JavaScript meta properties" does not have significantly relevant search results, so it should be easy to google for in the future.

# Andreas Rossberg (9 years ago)

On 17 January 2015 at 19:14, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

null is used to indicate no [[Prototype]], so it seem to me to be a better match for this situation.

Wouldn't the fact that null is a quasi-legal prototype strongly speak for using undefined here? Otherwise, it seems you couldn't distinguish Call invocations from Construct invocations with a prototype that has actually been set to null (which I suppose is legal?).

(In terms of proper option/maybe types, this is yet another case of a None vs Some(None) distinction.)

# Claude Pache (9 years ago)

new.target is a reference to the constructor, not the prototype, so the problem does not arise in practice.

But anyhow, I do think that undefined is semantically better here:

  • new.target === null means: new.target has been set to "no object".
  • new.target === undefined means: new.target has not been set.

When you execute a function body with the semantics of [[Construct]], the value of new.target is the original constructor on which new was applied. If it was possible to have the semantics of [[Construct]] with no original constructor, then new.target would be null (no-object).

But when you execute a function body with the semantics of [[Call]], there is no notion of "original constructor", and new.target is left with no value, i.e. undefined.

# Allen Wirfs-Brock (9 years ago)

On Jan 19, 2015, at 5:51 AM, Claude Pache wrote:

But anyhow, I do think that undefined is semantically better here:

  • new.target === null means: new.target has been set to "no object".
  • new.target === undefined means: new.target has not been set.

At the JS level, I don't actually think about new.target as something that is "settable". I think about it as an oracle that tells me about how this function was invoked. null means it was invoked "as a function". non-null means it was invoked as a constructor and the value is the object that new was applied to.

When you execute a function body with the semantics of [[Construct]], the value of new.target is the original constructor on which new was applied. If it was possible to have the semantics of [[Construct]] with no original constructor, then new.target would be null (no-object).

But it isn't. Reflect.construct ensures that an non-null value is passed to [[Construct]] as its second argument

But when you execute a function body with the semantics of [[Call]], there is no notion of "original constructor", and new.target is left with no value, i.e. undefined.

I originally intended new.target to use undefined is the sentinel value to indicated "called as a function". But as I wrote the spec. it felt better to use null in that role. I think it's because using null seems more special. undefined is used in so many places to indicated so many different things that it is hard to apply any generalized meaning to it. On the other hand, null is used in only a few places in the ES spec. so its use seems to draw attention to the specialness of those situations.

But, I'd have no problem with changing back to undefined if there is a consensus in favor of that.

It really makes very little difference as null and undefined are both falsey values, so the preferred way to write a "called as a function" these should probably be:

if (! new.target) ...
# Mark Volkmann (9 years ago)

Maybe this is wrong, but I'm in the habit of thinking that if something has a value of null, something in JavaScript code (mine or a library I'm using) explicitly set it to null. If something has a value of undefined, it was never set. For that reason, I'd prefer using undefined in this case over null.

# Isiah Meadows (9 years ago)

Okay. Thanks.