A few arrow function specification issues

# Allen Wirfs-Brock (13 years ago)

Here are a few design alternates that have come up as I work the specification draft for arrow functions

  1. Always strict? Should all arrow functions be considered strict functions?

Pros It's a new syntactic form, so it is it easy to make it be an implicit opt-in to strict mode. We generally want to encourage use of strict mode. If not, there would no way to to make an expression-bodied arrow function a strict function (other than by nesting it in strict code) Always strict eliminates the need for some of the arrow special case alternatives discussed below

Cons We shouldn't be trying to force use of strict mode. Programmers who don't know about strict mode may get confused by the application of strict mode semantics to arrow functions It would create a refactoring hazard for non-strict code.

  1. Redeclaring eval in non-strict arrow functions

Should strict mode eval declaration/assignment restrictions be be imposed upon non-strict arrow functions?

I propose disallow binding eval or assigning to it all arrow functions

  1. Declaring arguments as a formal parameter, or local binding in a non-strict arrow function

The wiki proposal says arguments can't be used as an expression primary but doesn't say anything about declarations

I propose binding or assigning or referencing arguments within a arrow function.

  1. Should it be a dynamic error to try to use apply/call to set the this binding of an arrow function.

Cons To much existing code speculatively binding the this value when invoking a function.

I propose that call/apply simply ignore the this value when invoked on an arrow function.

  1. Should arrow functions define the [[HasInstance]] internal method. In other words should should: obj instanceof () => {}

do? If it doesn't have [[HasInstance]] then instanceof would throw a type error. Alternatively, it could have a [[HasInstance]] that always returns false. We have already decided that arrow functions don't have a [[Construct]] internal method nor a prototype property.

I propose that arrow functions do not have a [[HasInstance]] internal method.

  1. Do arrow functions need to have per instance "caller" and "arguments" poison pill properties?

I propose no, because they are a new feature. But we can include a NOTE warning against providing their non-standard legacy implementation.

7)All of the above questions also apply to functions defined using concise method syntax in object literals or classes. Should the same answers apply to them?

# Brendan Eich (13 years ago)

Allen Wirfs-Brock wrote:

  1. Always strict? Should all arrow functions be considered strict functions?

Pros P1. It's a new syntactic form, so it is it easy to make it be an implicit opt-in to strict mode. P2. We generally want to encourage use of strict mode. P3. If not, there would no way to to make an expression-bodied arrow function a strict function (other than by nesting it in strict code) P4. Always strict eliminates the need for some of the arrow special case alternatives discussed below

Cons We shouldn't be trying to force use of strict mode. Programmers who don't know about strict mode may get confused by the application of strict mode semantics to arrow functions It would create a refactoring hazard for non-strict code.

Pros outweigh Cons in my book, on their face. In particular the ones I took the liberty of labeling P3 and P4.

I thought per 1JS that modules opt into strict mode (P1 but stronger).

P4 is enough by itself unless there's a big Con. I don't see one big enough to matter.

  1. Redeclaring eval in non-strict arrow functions

Should strict mode eval declaration/assignment restrictions be be imposed upon non-strict arrow functions?

I propose disallow binding eval or assigning to it all arrow functions

Yes, and implied strict mode handles this.

  1. Declaring arguments as a formal parameter, or local binding in a non-strict arrow function

The wiki proposal says arguments can't be used as an expression primary but doesn't say anything about declarations

I propose binding or assigning or referencing arguments within a arrow function.

With missing "to disallow", agreed.

  1. Should it be a dynamic error to try to use apply/call to set the this binding of an arrow function.

Cons To much existing code speculatively binding the this value when invoking a function.

I propose that call/apply simply ignore the this value when invoked on an arrow function.

Agreed. That's in the wiki proposal, as revised.

  1. Should arrow functions define the [[HasInstance]] internal method. In other words should should: obj instanceof () => {} do? If it doesn't have [[HasInstance]] then instanceof would throw a type error. Alternatively, it could have a [[HasInstance]] that always returns false. We have already decided that arrow functions don't have a [[Construct]] internal method nor a prototype property.

Yes, so it follows no [[HasInstance]]. This is an oversight in the proposal.

I propose that arrow functions do not have a [[HasInstance]] internal method.

Agreed.

  1. Do arrow functions need to have per instance "caller" and "arguments" poison pill properties?

I propose no, because they are a new feature. But we can include a NOTE warning against providing their non-standard legacy implementation.

NOTE sounds good, and we should not poison new ground.

7)All of the above questions also apply to functions defined using concise method syntax in object literals or classes. Should the same answers apply to them?

Question 4 does not -- methods must have dynamic |this| and you can substitute another object via .apply/.call.

Otherwise I'd make them the same. I suspect there will be arguments to support new and instanceof. Use a function-valued property if you need to (my response).

# Angus Croll (13 years ago)
  1. Should it be a dynamic error to try to use apply/call to set the this

binding of an arrow function.

Cons To much existing code speculatively binding the this value when invoking

a function.

I propose that call/apply simply ignore the this value when invoked on an

arrow function.

What is the pro of ignoring explicit |this| binding instructions in call/apply on arrow functions? What is the con of continuing to allow legacy code to speculatively bind the |this| value when invoking any function? Why is it so important that fat arrows do a hard |this| binding?

# Taka Kojima (13 years ago)

I am in agreement with Angus on this one.

If there is no skinny arrow, hard |this| binding should not be part of the spec. Fat arrow functions should default to lexical |this|, but if there is no skinny arrow, it should not be a hard binding and call/apply should be allowed, as well as bind,

# Domenic Denicola (13 years ago)

-----Original Message----- From: es-discuss-bounces at mozilla.org [mailto:es-discuss- bounces at mozilla.org] On Behalf Of Angus Croll Sent: Saturday, April 21, 2012 16:03 To: Allen Wirfs-Brock Cc: es-discuss Subject: Re: A few arrow function specification issues

  1. Should it be a dynamic error to try to use apply/call to set the this binding of an arrow function.

Cons To much existing code speculatively binding the this value when invoking a function.

I propose that call/apply simply ignore the this value when invoked on an arrow function.

What is the pro of ignoring explicit |this| binding instructions in call/apply on arrow functions? What is the con of continuing to allow legacy code to speculatively bind the |this| value when invoking any function? Why is it so important that fat arrows do a hard |this| binding?

It's important, as someone who hands off an arrow function to another part of the system, to ensure that this means what it meant while I was originally writing the code. This guarantee is vital for predictability of behavior. Consider

let mapped = array.map((el) => el * this.x)

If I cannot guarantee a lexical this, I am back to programming with let that = this, which is part of what arrow functions are trying to avoid. The only alternative is reading the source code and/or spec for every system that I hand off an arrow function to, since I need to know if they will clobber the lexical this I was trying to program against.

Note that this isn't a security issue---I'm not worried about "malicious code" messing me up. I'm simply trying to juggle the minimum number of factors on my precious brainstack, and when I'm trying to get a mapped array, I really don't want to think about whether map is going to mess with my this.

# Axel Rauschmayer (13 years ago)

I am in agreement with Angus on this one.

If there is no skinny arrow, hard |this| binding should not be part of the spec. Fat arrow functions should default to lexical |this|, but if there is no skinny arrow, it should not be a hard binding and call/apply should be allowed, as well as bind,

IMHO, the spec got it exactly right. We have a chance to really simplify things and introduce a clear distinction:

  • Methods – dynamic this: Use a concise method definition inside an object literal (or, hopefully, inside a class declaration).
  • Non-method functions – lexical this: Use an arrow function.

Anything else is rare (see Kevin Smith’s JS code survey) and non-methods with dynamic this are usually an anti-pattern. If you really need it, there are always old-school functions.

As for switching between dynamic this and lexical this depending on whether a function is called as a method or as a function. At first glance, it sounds like a good idea, like the best of both worlds. However, I’m with Domenic Denicola: it’s too brittle – a function shouldn’t work radically (and silently!) different depending on how it is invoked. Switching to this = undefined is bearable for old-school non-method functions, but switching to lexical this will lead to many hard-to-debug errors.

# Taka Kojima (13 years ago)

It's important, as someone who hands off an arrow function to another part of the system, to ensure that this means what it meant while I was originally writing the code. This guarantee is vital for predictability of behavior. Consider let mapped = array.map((el) => el * this.x) If I cannot guarantee a lexical this, I am back to programming with let that = this, which is part of what arrow functions are trying to avoid. The only alternative is reading the source code and/or spec for every system that I hand off an arrow function to, since I need to know if they will clobber the lexical this I was trying to program against. Note that this isn't a security issue---I'm not worried about "malicious code" messing me up. I'm simply trying to juggle the minimum number of factors on my precious brainstack, and when I'm trying to get a mapped array, I really don't want to think about whether map is going to mess with my this.

I understand your argument, but I think it is more important to be able to switch in full to the new function operator(s), not sometimes one, other times the other.

function is old, it supports deprecated/old things like arguments and caller. This kind of says bind/call/apply are old too and in some fashion discourages their use. Even if that is not the intent, it happens by association,

Using => but being forced to using function anytime I want dynamic this

just doesn't work.

If the goal is to discourage use of bind/call/apply on functions (this doesn't include methods), then I would say this spec makes sense, otherwise, we need a non hard |this| binding as part of fat arrows, or we need skinny arrow.

# Angus Croll (13 years ago)

a function shouldn’t work radically (and silently!) different depending

on how it is invoked

every current JS function behaves exactly this way :-)

I'm painfully aware that I sound like a broken record on this, but introducing a hard-bound function option while continuing to suport dynamic-bound functions everywhere else is not going to simplify anything. Another function should not need to know how its function arguments were created in order to work properly - thats a terrible anti-functional anti-pattern!

Imagine....

function(fn) { //.... if (fn.prototype) { fn.apply(x); } else { throw Error("I can't call your function in my context"); } }

# Axel Rauschmayer (13 years ago)

a function shouldn’t work radically (and silently!) different depending on how it is invoked

every current JS function behaves exactly this way :-)

this when not invoking a function as a method:

  1. Bearable: this === undefined
  2. Nasty: this === window
  3. Very nasty: lexical this

I'm painfully aware that I sound like a broken record on this, but introducing a hard-bound function option while continuing to suport dynamic-bound functions everywhere else is not going to simplify anything.

The point is that dynamic-bound functions will mostly go away in ES.next. There will mainly be methods and arrow functions. With super-references, methods become more than functions with dynamic this, anyway!

Another function should not need to know how its function arguments were created in order to work properly - thats a terrible anti-functional anti-pattern!

Counter-question: Isn’t it clear when you create a function whether it is going to be a non-method function or a method? What is the use case for a non-method function with dynamic this?

Sometimes you might want to pass a method as a callback, but then you need to convert it to a non-method function, anyway (e.g. via bind()).

# Angus Croll (13 years ago)

On Sat, Apr 21, 2012 at 1:56 PM, Axel Rauschmayer <axel at rauschma.de> wrote:

Counter-question: Isn’t it clear when you create a function whether it is going to be a non-method function or a method?

It's clear to the implementer - Its not clear to a function that gets it as an argument - unless fn.prototype is checked

What is the use case for a non-method function with dynamic this?

a) Invoke callback in my context b) Functional mixins c) Namespacing by call/apply

# Axel Rauschmayer (13 years ago)

On Sat, Apr 21, 2012 at 1:56 PM, Axel Rauschmayer <axel at rauschma.de> wrote: Counter-question: Isn’t it clear when you create a function whether it is going to be a non-method function or a method?

It's clear to the implementer - Its not clear to a function that gets it as an argument - unless fn.prototype is checked

I would argue that – in ES.next – whenever a function is passed as an argument, one should always assume that it is a non-method function and completely ignore this.

What is the use case for a non-method function with dynamic this?

a) Invoke callback in my context

Alternative: introduce an additional parameter for the context.

b) Functional mixins

Alternative: use object literals to specify those.

c) Namespacing by call/apply

Alternative: use modules.

Additionally, there are generic methods. But those are methods. And they would work better as non-method functions, anyway. IIRC, there is a proposal for making them available as such (e.g. via a module). Lastly, the main raison d’être of generic functions was arguments. With arguments on its way out, we’ll need them less.

If we can make this work, it will make JavaScript a much simpler language, much easier to understand for newcomers. Hence, I’m not trying to be glib, above, I’m arguing in favor of making things simpler.

Currently, quite a bit of cleverness is needed for figuring out how to handle this (bound, unbound, etc.). If old-school functions are replaced by class declarations (constructors), arrow functions (non-method functions) and method definitions (methods), one will automatically do the right thing.

# Angus Croll (13 years ago)

On Sat, Apr 21, 2012 at 3:06 PM, Axel Rauschmayer <axel at rauschma.de> wrote:

On Sat, Apr 21, 2012 at 1:56 PM, Axel Rauschmayer <axel at rauschma.de>wrote:

Counter-question: Isn’t it clear when you create a function whether it is going to be a non-method function or a method?

It's clear to the implementer - Its not clear to a function that gets it as an argument - unless fn.prototype is checked

I would argue that – in ES.next – whenever a function is passed as an argument, one should always assume that it is a non-method function and completely ignore this.

This makes me sad. Seems like functions are going to be a little less first class than they were before - and for fairly arbitrary reasons (the introduction of tight-bound |this| in one syntax varietal). And not being able to assume call and apply will work on any given function feels like the road to deprecation.

What is the use case for a non-method function with dynamic this?

a) Invoke callback in my context

Alternative: introduce an additional parameter for the context.

Again - why do we need to get clunky suddenly?

b) Functional mixins

Alternative: use object literals to specify those.

Functional mixins are flexible and intuitive. I've used them to great effect. Yes there are alternatives but again a little piece of the language dies.

c) Namespacing by call/apply

Alternative: use modules.

See above.

Additionally, there are generic methods. But those are methods. And they would work better as non-method functions, anyway. IIRC, there is a proposal for making them available as such (e.g. via a module). Lastly, the main raison d’être of generic functions was arguments. With arguments on its way out, we’ll need them less.

If we can make this work, it will make JavaScript a much simpler language, much easier to understand for newcomers. Hence, I’m not trying to be glib, above, I’m arguing in favor of making things simpler.

Overall I don't see this getting simpler. Six |this| rules instead of five; static and dynamic |this| binding instead of just dynamic; loss of guarantee re. the nature of function arguments.

Currently, quite a bit of cleverness is needed for figuring out how to handle this (bound, unbound, etc.).

Yes, but it hasn't held the language back. JS is mushrooming, and the growth of new and brilliant code idioms over the last decade has been amazing. Curbing the dynamic nature of JavaScript might be a more serious risk to innovation than continuing to require a bit of cleverness.

In any case I suspect adding yet another rule of |this| binding will mean even more cleverness is needed in ES6.

If old-school functions are replaced by class declarations (constructors), arrow functions (non-method functions) and method definitions (methods), one will automatically do the right thing.

Thats three types of functions now. Our legacy code is going to be confused.

# Brendan Eich (13 years ago)

Angus Croll wrote:

On Sat, Apr 21, 2012 at 3:06 PM, Axel Rauschmayer <axel at rauschma.de <mailto:axel at rauschma.de>> wrote:

On Sat, Apr 21, 2012 at 1:56 PM, Axel Rauschmayer
<axel at rauschma.de <mailto:axel at rauschma.de>> wrote:

    Counter-question: Isn’t it clear when you create a function
    whether it is going to be a non-method function or a method? 


It's clear to the implementer - Its not clear to a function that
gets it as an argument - unless fn.prototype is checked
I would argue that – in ES.next – whenever a function is passed as
an argument, one should always assume that it is a non-method
function and completely ignore `this`.

This makes me sad. Seems like functions are going to be a little less first class than they were before

There is no "before". Today, no ES6, you pass to another module written by someone else (or by an older and forgotten "you") a function that (a) you wrote and (b) uses |this|, you had better .bind(that) or otherwise make sure it receives the right |this|.

People fail to do this all the time. The easiest bug is just to use |this| in a function expression assuming it will be the same as in the enclosing function. Seasoned programmers make this mistake, it's the safety-last nature of always-dynamic |this|.

Given the requirement today that you bind |this| or don't use it, there's nothing less "first class" in the future. The problem exists today, and indeed some analyses showed 80-90% or more of functions either bind |this| or do not use it. These are all candidates for arrow.

But if we make arrows allow |this| override, then the roughly half of that 80-90% that want to bind |this| cannot be sure a caller won't override via .apply or .call (why not through a method reference too?). We'll be back in the "I forgot to use .bind(that) or var that = this; on the outside, the footgun fired all too often.

  • and for fairly arbitrary reasons (the introduction of tight-bound |this| in one syntax varietal).

There's nothing arbitrary about fixing the hazard with new syntax that reliably binds |this|. The argument to have is whether -> should be

added too.

And not being able to assume call and apply will work on any given function feels like the road to deprecation.

You cannot assume |this| can be overridden by apply and call today:

js> function f(){"use strict"; return this.x}

js> f.apply({x:42})

42 js> g = f.bind({x:99})

function f() {[native code]} js> g()

99 js> g.apply(101)

99

(No ES6 here, and ES5 not required -- bind preceded ES5 by many years and can be written in JS.)

Assuming something not guaranteed is a mistake. The fix is not to keep assuming and propagate the assumption (that |this| can be overridden) to new and better short-function forms.

# Axel Rauschmayer (13 years ago)

I would argue that – in ES.next – whenever a function is passed as an argument, one should always assume that it is a non-method function and completely ignore this.

This makes me sad. Seems like functions are going to be a little less first class than they were before - and for fairly arbitrary reasons (the introduction of tight-bound |this| in one syntax varietal). And not being able to assume call and apply will work on any given function feels like the road to deprecation.

They still work, you just cannot set this, which you can’t, either, if you use bind: > function foo() { "use strict"; return this; } > foo.bind("hello").call("abc") 'hello'

What is the use case for a non-method function with dynamic this?

a) Invoke callback in my context

Alternative: introduce an additional parameter for the context.

Again - why do we need to get clunky suddenly?

I’d call it more explicit. Why use an OOP construct if, conceptually, it is just another (non-method) function parameter?

b) Functional mixins

Alternative: use object literals to specify those.

Functional mixins are flexible and intuitive. I've used them to great effect. Yes there are alternatives but again a little piece of the language dies.

Can you give an example?

c) Namespacing by call/apply

Alternative: use modules.

See above.

I’m already very happy with Node.js modules and AMDs. Can’t imagine myself going back to manual namespacing.

Additionally, there are generic methods. But those are methods. And they would work better as non-method functions, anyway. IIRC, there is a proposal for making them available as such (e.g. via a module). Lastly, the main raison d’être of generic functions was arguments. With arguments on its way out, we’ll need them less.

If we can make this work, it will make JavaScript a much simpler language, much easier to understand for newcomers. Hence, I’m not trying to be glib, above, I’m arguing in favor of making things simpler.

Overall I don't see this getting simpler. Six |this| rules instead of five; static and dynamic |this| binding instead of just dynamic; loss of guarantee re. the nature of function arguments.

Function arguments won’t change, I’d just expect passing this to a function to happen less. Thankfully, we’ll have the spread operator to take over most of apply’s duties.

To me, things become simpler, because I’ll automatically use the right tool:

  1. Instead of constructors, I have class declarations that set up subtyping correctly.
  2. Method definitions will make sure that super works and will be less to type. Dynamic this implies method to me.
  3. If I use a function expression inside a method, I always want it to have lexical this. I think that is the default that makes most sense, conceptually.

These are three rules, easy to follow: method versus (non-method) function versus object factory.

If old-school functions are replaced by class declarations (constructors), arrow functions (non-method functions) and method definitions (methods), one will automatically do the right thing.

Thats three types of functions now. Our legacy code is going to be confused.

A definite possibility. However, the only problem I can see is a function expecting to pass this to a callback. If the callback has been created via bind(), it is out of luck, already. Are there other problems?

# Kevin Smith (13 years ago)

I understand your argument, but I think it is more important to be able to switch in full to the new function operator(s), not sometimes one, other times the other.

Why? Arrow functions and traditional functions serve different semantic purposes. Why is it important to you that we essentially deprecate traditional 'function' syntax?

# Axel Rauschmayer (13 years ago)

Using => but being forced to using function anytime I want dynamic this just doesn't work.

That may be the crux of the matter. I’d say: In new code, use a method definition any time you want dynamic this. In old code, use a function expression.

# Herby Vojčík (13 years ago)

Angus Croll wrote:

On Sat, Apr 21, 2012 at 1:56 PM, Axel Rauschmayer <axel at rauschma.de <mailto:axel at rauschma.de>> wrote:

Counter-question: Isn’t it clear when you create a function whether
it is going to be a non-method function or a method?

It's clear to the implementer - Its not clear to a function that gets it as an argument - unless fn.prototype is checked

How is this different from checking the type of an argument? There are people who feel "safer" when the language checks the type for them. Then there is different school preferring dynamic typing (Smalltalk, Self, JS, ...), where the caller is to blame when it passes different type (and if the code must be foolproof, it should check somehow).

Do you always check all the argument if they are really numbers, strings, objects of concete type you want to get? I'd bet you don't.

This is the same.

# Andreas Rossberg (13 years ago)

On 21 April 2012 01:22, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

Here are a few design alternates that have come up as I work the specification draft for arrow functions

  1. Always strict? Should all arrow functions be considered strict functions?

Pros It's a new syntactic form, so it is it easy to make it be an implicit opt-in to strict mode. We generally want to encourage use of strict mode. If not, there would no way to to make an expression-bodied arrow function a strict function (other than by nesting it in strict code) Always strict eliminates the need for some of the arrow special case alternatives discussed below

Cons We shouldn't be trying to force use of strict mode. Programmers who don't know about strict mode may get confused by the application of strict mode  semantics to arrow functions It would create a refactoring hazard for non-strict code.

One more: It makes the rules for what mode applies where more complicated and less obvious.

To be honest, that suggestion confirms one of my fears about "1JS" -- ending up with a more complicated language with ad-hoc rules about which mode applies in which context. Please let's try to resist the temptation. As much as I would like to encourage strict mode, I think we should keep it orthogonal to other constructs as much as possible. I can bear tying it to modules, but let's not go any further.

  1. Redeclaring eval in non-strict arrow functions

Should strict mode eval declaration/assignment restrictions be be imposed upon non-strict arrow functions?

I propose disallow binding eval or assigning to it all arrow functions

Same here. If it's sloppy mode, let the sloppy mode rules apply as usual.

  1. Declaring arguments as a formal parameter, or local binding in a non-strict arrow function

The wiki proposal says arguments can't be used as an expression primary but doesn't say anything about declarations

I propose binding or assigning or referencing arguments within a arrow function.

I suppose the most natural semantics would be that, like 'this', ' arguments' is bound lexically from a surrounding function, if present. But that's perhaps too confusing, so I'd be fine with ruling out its use completely.

  1. Should it be a dynamic error to try to use apply/call to set the this binding of an arrow function.

Cons To much existing code speculatively binding the this value when invoking a function.

I propose that call/apply simply ignore the this value when invoked on an arrow function.

Yes, that is consistent with what happens today when you call/apply a function after 'bind'.

  1. Should arrow functions define the [[HasInstance]] internal method. In other words should should:    obj instanceof () => {} do? If it doesn't have [[HasInstance]] then instanceof would throw a type error.  Alternatively, it could have a [[HasInstance]] that always returns false. We have already decided that arrow functions don't have a [[Construct]] internal method nor a prototype property.

I propose that arrow functions do not have a  [[HasInstance]] internal method.

Agreed. It would be weird to support HasInstance in the absence of the other.

  1. Do arrow functions need to have per instance "caller" and "arguments" poison pill properties?

I propose no, because they are a new feature. But we can include a NOTE warning against providing their non-standard legacy implementation.

For simplicity and uniformity, I'd keep the same semantics as for ordinary functions. Don't special-case if there is no strong reason to do so.

  1. All of the above questions also apply to functions defined using concise method syntax in object literals or classes.  Should the same answers apply to them?

I'd prefer if concise method syntax stayed simple syntactic sugar for functions. Methods obviously need dynamic this. If you combine that with changes like the above, then you have implicitly introduced a third kind of function that cannot be described as (simple) syntactic sugar for any of the other two. That would be unfortunate, IMO.

# Alex Russell (13 years ago)

On Apr 23, 2012, at 10:15 AM, Andreas Rossberg wrote:

On 21 April 2012 01:22, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

Here are a few design alternates that have come up as I work the specification draft for arrow functions

  1. Always strict? Should all arrow functions be considered strict functions?

Pros It's a new syntactic form, so it is it easy to make it be an implicit opt-in to strict mode. We generally want to encourage use of strict mode. If not, there would no way to to make an expression-bodied arrow function a strict function (other than by nesting it in strict code) Always strict eliminates the need for some of the arrow special case alternatives discussed below

Cons We shouldn't be trying to force use of strict mode. Programmers who don't know about strict mode may get confused by the application of strict mode semantics to arrow functions It would create a refactoring hazard for non-strict code.

One more: It makes the rules for what mode applies where more complicated and less obvious.

Unsurprisingly, I agree.

To be honest, that suggestion confirms one of my fears about "1JS" -- ending up with a more complicated language with ad-hoc rules about which mode applies in which context. Please let's try to resist the temptation. As much as I would like to encourage strict mode, I think we should keep it orthogonal to other constructs as much as possible. I can bear tying it to modules, but let's not go any further.

  1. Redeclaring eval in non-strict arrow functions

Should strict mode eval declaration/assignment restrictions be be imposed upon non-strict arrow functions?

I propose disallow binding eval or assigning to it all arrow functions

Same here. If it's sloppy mode, let the sloppy mode rules apply as usual.

  1. Declaring arguments as a formal parameter, or local binding in a non-strict arrow function

The wiki proposal says arguments can't be used as an expression primary but doesn't say anything about declarations

I propose binding or assigning or referencing arguments within a arrow function.

I suppose the most natural semantics would be that, like 'this', ' arguments' is bound lexically from a surrounding function, if present. But that's perhaps too confusing, so I'd be fine with ruling out its use completely.

We might be able to do soft binding without much ambiguity. I'll post something here about it under separate cover.

  1. Should it be a dynamic error to try to use apply/call to set the this binding of an arrow function.

Cons To much existing code speculatively binding the this value when invoking a function.

I propose that call/apply simply ignore the this value when invoked on an arrow function.

Yes, that is consistent with what happens today when you call/apply a function after 'bind'.

  1. Should arrow functions define the [[HasInstance]] internal method. In other words should should: obj instanceof () => {} do? If it doesn't have [[HasInstance]] then instanceof would throw a type error. Alternatively, it could have a [[HasInstance]] that always returns false. We have already decided that arrow functions don't have a [[Construct]] internal method nor a prototype property.

I propose that arrow functions do not have a [[HasInstance]] internal method.

Agreed. It would be weird to support HasInstance in the absence of the other.

  1. Do arrow functions need to have per instance "caller" and "arguments" poison pill properties?

I propose no, because they are a new feature. But we can include a NOTE warning against providing their non-standard legacy implementation.

For simplicity and uniformity, I'd keep the same semantics as for ordinary functions. Don't special-case if there is no strong reason to do so.

  1. All of the above questions also apply to functions defined using concise method syntax in object literals or classes. Should the same answers apply to them?

I'd prefer if concise method syntax stayed simple syntactic sugar for functions. Methods obviously need dynamic this. If you combine that with changes like the above, then you have implicitly introduced a third kind of function that cannot be described as (simple) syntactic sugar for any of the other two. That would be unfortunate, IMO.

/Andreas


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

-- Alex Russell slightlyoff at google.com slightlyoff at chromium.org alex at dojotoolkit.org BE03 E88D EABB 2116 CC49 8259 CF78 E242 59C3 9723

# Kevin Smith (13 years ago)

I'd prefer if concise method syntax stayed simple syntactic sugar for functions. Methods obviously need dynamic this. If you combine that with changes like the above, then you have implicitly introduced a third kind of function that cannot be described as (simple) syntactic sugar for any of the other two. That would be unfortunate, IMO.

FWIW, I agree.

# Brendan Eich (13 years ago)

Andreas Rossberg wrote:

To be honest, that suggestion confirms one of my fears about "1JS" -- ending up with a more complicated language with ad-hoc rules about which mode applies in which context. Please let's try to resist the temptation. As much as I would like to encourage strict mode, I think we should keep it orthogonal to other constructs as much as possible. I can bear tying it to modules, but let's not go any further.

It's a good point (and I'm not one to "encourage strict mode" if there's no payoff for developers, but before agreeing, can you enumerate the cases that matter inside an arrow function body?

Without arguments runtime semantic shifts, and with |this| lexical, there aren't many strict mode changes left IIRC, and they are pretty edgy edge cases.

# Herby Vojčík (13 years ago)

Andreas Rossberg wrote:

On 21 April 2012 01:22, Allen Wirfs-Brock<allen at wirfs-brock.com> wrote:

  1. All of the above questions also apply to functions defined using concise method syntax in object literals or classes. Should the same answers apply to them?

I'd prefer if concise method syntax stayed simple syntactic sugar for functions. Methods obviously need dynamic this. If you combine that

But they are not, already. There is that thing with home / defineMethod and super-expressions (and I am for it, it is a good thing).

# Allen Wirfs-Brock (13 years ago)

On Apr 23, 2012, at 8:19 AM, Brendan Eich wrote:

Andreas Rossberg wrote:

To be honest, that suggestion confirms one of my fears about "1JS" -- ending up with a more complicated language with ad-hoc rules about which mode applies in which context. Please let's try to resist the temptation. As much as I would like to encourage strict mode, I think we should keep it orthogonal to other constructs as much as possible. I can bear tying it to modules, but let's not go any further.

It's a good point (and I'm not one to "encourage strict mode" if there's no payoff for developers, but before agreeing, can you enumerate the cases that matter inside an arrow function body?

Without arguments runtime semantic shifts, and with |this| lexical, there aren't many strict mode changes left IIRC, and they are pretty edgy edge cases.

See Annex C. Some strict mode highlights:

Assignment to an unbound name throws instead of creating a property of the global object

With statements are disallowed

direct eval can't instantiate new binding in the enclosing environment

duplicate formal parameter names are disallowed (I suggest we add this restriction to arrow functions even if we say they aren't inherently strict. )

# Brandon Benvie (13 years ago)
  1. Do arrow functions need to have per instance "caller" and "arguments" poison pill properties?

I propose no, because they are a new feature. But we can include a NOTE warning against providing their non-standard legacy implementation.

For simplicity and uniformity, I'd keep the same semantics as for ordinary functions. Don't special-case if there is no strong reason to do so.

Can arrow functions just not have arguments, caller, and name at all? I have to say, it's really annoying having to special case these properties when trying to create function proxies that are mostly virtual, as they are non-configurable, non-writable, and own properties.

# Brendan Eich (13 years ago)

Allen Wirfs-Brock wrote:

On Apr 23, 2012, at 8:19 AM, Brendan Eich wrote:

Andreas Rossberg wrote:

To be honest, that suggestion confirms one of my fears about "1JS" -- ending up with a more complicated language with ad-hoc rules about which mode applies in which context. Please let's try to resist the temptation. As much as I would like to encourage strict mode, I think we should keep it orthogonal to other constructs as much as possible. I can bear tying it to modules, but let's not go any further. It's a good point (and I'm not one to "encourage strict mode" if there's no payoff for developers, but before agreeing, can you enumerate the cases that matter inside an arrow function body?

Without arguments runtime semantic shifts, and with |this| lexical, there aren't many strict mode changes left IIRC, and they are pretty edgy edge cases.

See Annex C. Some strict mode highlights:

Assignment to an unbound name throws instead of creating a property of the global object

Right. This one I want in new forms, and it's not ad-hoc if arrows imply strict mode. Limiting strict mode implication to modules is just as arbitrary and more user-hostile in my view. No one writing arrows wants to create globals implicitly, only to save themselves by typing a "use strict"; pseudo-pragma!

With statements are disallowed

Ditto^2.

direct eval can't instantiate new binding in the enclosing environment

Ditto^3.

duplicate formal parameter names are disallowed

We disallow duplicates if destructuring formal parameters appear in any parameter list, in SpiderMonkey. We discussed doing this for any function with destructuring parameters as part of the 1JS thread early this year. I forget whether you spec'ed it already.

In that earlier discussion we did not agree that using a destructuring formal parameter in a 'function' declaration or expression opts the body of the function into strict mode. More the reverse -- one formal parameter novelty does not say "strict throughout". But it can certainly say "no duplicate formals" and no one minds. Duplicate formals are a botch from ES1, added only to match JScript, IIRC.

(I suggest we add this restriction to arrow functions even if we say they aren't inherently strict. )

Agreed.

1JS is about new syntax as opt-in for new semantics. Those new semantics can be strict in some or all respects. There is nothing more ad-hoc about this than requiring "use strict"; to opt-in, no one wants the botches you enumerate, and the implementations already have strict mode factored mostly to compile time and can impute strictness to arrows.

Really, the botches you enumerate are botches. They should not be perpetuated into new function or module syntax where the body is introduced by a keyword that can imply strictness. Neither users nor implementors want this. The philosphical purity of separating concerns is an abstraction that is hostile to the best interests of users from all testimony I've heard [*].

/be

[*] I've never heard from anyone defending any of the botches listed above except for 'with', and when I push, it turns out people are using 'with' to make PHP-style templates -- but the requirement for dynamic scope is a phantom and one can generate even more efficient templates using Function or eval (and libraries do).

# Brendan Eich (13 years ago)

Brandon Benvie wrote:

> 6) Do arrow functions need to have per instance "caller" and
"arguments" poison pill properties?
>
> I propose no, because they are a new feature. But we can include
a NOTE warning against providing their non-standard legacy
implementation.

For simplicity and uniformity, I'd keep the same semantics as for
ordinary functions. Don't special-case if there is no strong reason to
do so. 

Can arrow functions just not have arguments, caller, and name at all?

Agreed on it being better to leave these off. Do not poison new ground.

I have to say, it's really annoying having to special case these properties when trying to create function proxies that are mostly virtual, as they are non-configurable, non-writable, and own properties.

This seems like an issue for direct proxies that we should discuss in a separate thread. Apologies if I already missed it.

# Brendan Eich (13 years ago)

Brendan Eich wrote:

Without arguments runtime semantic shifts, and with |this| lexical, there aren't many strict mode changes left IIRC, and they are pretty edgy edge cases.

Dave Herman pointed out the shift for |this|-binding in function nested in arrow, under the proposal that arrow implies strict mode:

(x, y) => { obj.m = function(…){…} }

Again the break if that arrow is strict is for edge cases, not anything calling obj.m(...) or via prototype delegation. obj.m.call(undefined, ...) would not substitute the global object, and primitives would not be boxed.

True enough, but I hang tough on wanting arrows to imply strictness. I may be wrong but the edge cases cited so far (global variable creation by assignment, 'with', direct eval injecting 'var' into its dynamic scope) along with this |this|-boxing one are underwhelming.

The other good point that came out in discussion with Dave was that module as implicitly strict works better (depending on your belief about future uses) than arrow as implicitly strict would, because (a) modules are bigger; and/or (b) modules are top-level (nesting only in other modules up to the top level) and cannot nest in functions or expressions.

I buy that as a one-off argument for imputing strictness to module bodies. I still think arrows could be next in line, knocking at the door, asking why they are getting the brush-off.

# David Herman (13 years ago)

On Apr 21, 2012, at 1:38 PM, Angus Croll wrote:

a function shouldn’t work radically (and silently!) different depending on how it is invoked

every current JS function behaves exactly this way :-)

No, not at all. What Axel is saying is that you're proposing a new distinction that does not exist in JS. You cannot distinguish whether a function was called as a method, as a function, or via .call/.apply. There's no way to tell. All you have is the receiver value bound to this, however it was passed in. Your function can decide whether or not to disregard the receiver entirely, but it can't tell where it came from.

The caller has the freedom to choose how it provides the receiver:

f()
obj.m = f; obj.m()
f.call(obj)
f.apply(obj, [])

but the callee can't tell the difference between f.call(null) and f().

I'm painfully aware that I sound like a broken record on this, but introducing a hard-bound function option while continuing to suport dynamic-bound functions everywhere else is not going to simplify anything. Another function should not need to know how its function arguments were created in order to work properly - thats a terrible anti-functional anti-pattern!

There's no difference whatsoever between a function with a lexically-bound this and a function that completely dis its this argument. This is simply a reality of JavaScript today and forever: every function has an API that indicates what it expects of its this argument and what it will do with it. If you write a function that ignores its this argument, your callers have to know that they can't change your function's behavior by passing a different this.

Put differently: the lexical this syntax is a convenient way to create a non-method function, a function that ignores its receiver.

# David Herman (13 years ago)

On Apr 23, 2012, at 2:45 PM, David Herman wrote:

You cannot distinguish whether a function was called as a method, as a function, or via .call/.apply. There's no way to tell.

PS Well, there's stack inspection, but we're all grownups here.

# David Herman (13 years ago)

On Apr 23, 2012, at 2:44 PM, Brendan Eich wrote:

Brendan Eich wrote:

Without arguments runtime semantic shifts, and with |this| lexical, there aren't many strict mode changes left IIRC, and they are pretty edgy edge cases.

True enough, but I hang tough on wanting arrows to imply strictness. I may be wrong but the edge cases cited so far (global variable creation by assignment, 'with', direct eval injecting 'var' into its dynamic scope) along with this |this|-boxing one are underwhelming.

IMO, this decision hangs on whether we think strict mode can be thought of as a "cleaning up" that will mostly just catch bugs, resulting in failing faster but otherwise not changing program behavior significantly.

POSITION "CLEANUP": If it's just a cleanup, then it makes sense to introduce strict mode in a bunch of places in the language. It'll catch bugs, and for the most part people won't have to think to themselves "is this strict code?"

POSITION "MODE": If it's something that is likely to change behavior in meaningful ways other than failing faster, then it's something programmers will have to be mindful of. In that case, having multiple constructs that implicitly introduce strict mode imposes a burden on programmers: they have to know which features are strict and which ones aren't.

Every fiber of my being screams MODE. Brendan argues CLEANUP based on the rationale that the non-error semantic changes of strict mode are unlikely edge cases. This is the strongest argument against MODE. I can't prove it wrong, but it's a risky bet. If it turns out to be the case that in practice you need to keep track of whether you're in strict mode, then weak programmers who don't know better will end up with a confusing mess, and strong programmers will prophylactically make sure to put their entire programs in strict mode rather than memorize which subset of syntaxes opt in. Since strong programmers have the option to do that anyway even without multiple implicit opt-ins, why take the risk?

Pascal^H^H^H^H^H^H

# Domenic Denicola (13 years ago)

As a day-to-day user who was not using strict until recently (stubborn other team member for the loss), I can say that moving to strict was much more a "cleanup" experience than a "mode" experience, with only a few small exceptions:

  1. Poison-pilling arguments.callee: some code on the internet (notably 1, but elsewhere too) uses this property.

  2. Throw on deleteing non-configurables: unlike the other throw-on-doing-something-bad, deleteing non-configurable properties was something we actually did on purpose. E.g. using it to clear an "entry" in a "map", whether or not that entry was ever filled. (Cf. 2.) We never tried writing to a non-writable property, because that would cause bugs, but deleteing a property that doesn't exist was a common pattern.


Otherwise, it was just cleanup: we got to get rid of our global detector (setInterval(compareWindowPropertiesToLastTimeYouChecked(), 1000)), never missed with or evil-eval, and due to a V8 bug never had boxed this in the first place. We're using it transparently throughout the codebase, in fact, due to using an XHR+eval module loader that can insert the "use strict" pragma before evaling.

# Anton Kovalyov (13 years ago)

My two cents. A little over a year ago, I went over our JavaScript code here at Disqus and made sure that 99% of it is in strict mode. This was definitely a code cleanup aiming at catching variable leaks and other small bugs.

# Brandon Benvie (13 years ago)

Strict mode delete non-configurable is one of the only offenders on the "this really shouldn't be an error" list. The "useful functionality no longer allowed" list is a couple of key things: caller for debug tracing, and var in define. The latter was an issue with Narcissus running in V8 --harmony as of recent, though I think it's fixed now. (prohibited with good reason, but providing irreplaceable functionality)

# Brandon Benvie (13 years ago)

var in eval I meant (and const in Narcissus's case)

# John J Barton (13 years ago)

Ok I gotta testify for the other side: use strict is not all roses. I hit three problems with 'use strict':

  1. I wrote the following code in JavaScript:

function register(otherWindow, local, options) {

var remote = Q_COMM.Connection(otherWindow, local, options);

remote.discover = function (remoteName) {...}

return remote; }

Upon calling the function I was surprised to find remote.discover was not set. After a long debug session I discovered that Q_COMM had frozen 'remote', but in order for me, the library user to get an error message I had 'use strict'. In my opinion this is a bug.

  1. Web Inspector has a bug related to use strict: code.google.com/p/chromium/issues/detail?id=114653

  2. The typical solution for obtaining a reference to the global object:

var global = (function() { return this; })();

fails in 'use strict'. As Domenic tells me, you have use

var global = Function('return this')();

These are not fundamental problems with 'use strict', they are practical problems caused by fragmenting the language in to modes.

jjb

# Allen Wirfs-Brock (13 years ago)

On Apr 23, 2012, at 4:59 PM, Domenic Denicola wrote:

As a day-to-day user who was not using strict until recently (stubborn other team member for the loss), I can say that moving to strict was much more a "cleanup" experience than a "mode" experience, with only a few small exceptions:

  1. Poison-pilling arguments.callee: some code on the internet (notably 1, but elsewhere too) uses this property.

  2. Throw on deleteing non-configurables: unlike the other throw-on-doing-something-bad, deleteing non-configurable properties was something we actually did on purpose. E.g. using it to clear an "entry" in a "map", whether or not that entry was ever filled. (Cf. 2.) We never tried writing to a non-writable property, because that would cause bugs, but deleteing a property that doesn't exist was a common pattern.

The delete issue is very much along the lines of what I was referring to in another thread3 today regarding "failure oblivious computing". I just don't think I see a big benefit from a throw in the situation of deleting a non-configurable property, particularly since there was already another mechanism (delete operator returns false) that indicates that the delete could not be performed.

IMO, this the delete strict mode throw was unnecessary and borders on being a bad idea. Perhaps we could remove it from ES6. How much strict mode code do we think is going to actually be dependent on getting that exception?

# Mark S. Miller (13 years ago)

On Mon, Apr 23, 2012 at 5:47 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:

On Apr 23, 2012, at 4:59 PM, Domenic Denicola wrote:

As a day-to-day user who was not using strict until recently (stubborn other team member for the loss), I can say that moving to strict was much more a "cleanup" experience than a "mode" experience, with only a few small exceptions:

  1. Poison-pilling arguments.callee: some code on the internet (notably 1, but elsewhere too) uses this property.

  2. Throw on deleteing non-configurables: unlike the other throw-on-doing-something-bad, deleteing non-configurable properties was something we actually did on purpose. E.g. using it to clear an "entry" in a "map", whether or not that entry was ever filled. (Cf. 2.) We never tried writing to a non-writable property, because that would cause bugs, but deleteing a property that doesn't exist was a common pattern.

The delete issue is very much along the lines of what I was referring to in another thread[3] today regarding "failure oblivious computing". I just don't think I see a big benefit from a throw in the situation of deleting a non-configurable property, particularly since there was already another mechanism (delete operator returns false) that indicates that the delete could not be performed.

IMO, this the delete strict mode throw was unnecessary and borders on being a bad idea. Perhaps we could remove it from ES6. How much strict mode code do we think is going to actually be dependent on getting that exception?

-1.

The "failure oblivious computing" stuff is fascinating, but I wouldn't try it at home. Such code proceeds silently after it has lost integrity. Not great for anything important. Completely useless for code that must maintain integrity under adversarial conditions.

# Allen Wirfs-Brock (13 years ago)

On Apr 23, 2012, at 6:09 PM, Mark S. Miller wrote:

On Mon, Apr 23, 2012 at 5:47 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

...

The delete issue is very much along the lines of what I was referring to in another thread[3] today regarding "failure oblivious computing". I just don't think I see a big benefit from a throw in the situation of deleting a non-configurable property, particularly since there was already another mechanism (delete operator returns false) that indicates that the delete could not be performed.

IMO, this the delete strict mode throw was unnecessary and borders on being a bad idea. Perhaps we could remove it from ES6. How much strict mode code do we think is going to actually be dependent on getting that exception?

-1.

The "failure oblivious computing" stuff is fascinating, but I wouldn't try it at home. Such code proceeds silently after it has lost integrity. Not great for anything important. Completely useless for code that must maintain integrity under adversarial conditions.

The point is that much of what is done on the web is not high integrity computation. It is essential that high integrity be possible, when it is required. But forcing all computation into the high integrity category seems like as bad an idea as forcing all computation to be low integrity. I really wonder how successful JS would have been if it had started out as a high integrity language.

# Mark S. Miller (13 years ago)
# John J Barton (13 years ago)

+1 High integrity engineering of components supports low integrity integration essential for low cost adaptable systems. We have scripting for the same reason we carpenters. We could build a house using a computer milling machine but no one could afford it; we don't want JavaScript to enforce high precision at the cost of flexibility. jjb

# Brandon Benvie (13 years ago)

This is why I posited an explicit switch. Right now we're all talking about secondary triggers for a very important component. Why isn't it just an explicit choice? Why can't I install a foot gun where I know I have foot armor plating? The goal being that when my users, without such armor, are less likely to be exposed to it?

# Douglas Crockford (13 years ago)

On 4/23/2012 6:41 PM, Mark S. Miller wrote:

On Mon, Apr 23, 2012 at 6:30 PM, Allen Wirfs-Brock <allen at wirfs-brock.com <mailto:allen at wirfs-brock.com>> wrote:

The point is that much of what is done on the web is not high
integrity computation. It is essential that high integrity be
possible, when it is required. But forcing all computation into the
high integrity category seems like as bad an idea as forcing all
computation to be low integrity.  I really wonder how successful JS
would have been if it had started out as a high integrity language.

Yes, I think that's a good point.

No, that is not a good point. The strange ascendance of JS can best be described as miraculous. It succeed despite its low integrity, not because of it.

Our problem is not to figure out how to make this language popular. We have somehow already managed that through amazing luck. I think our problem now is to disarm the array of toeguns while minimizing breakage as much as possible, and to avoid installing new toeguns. I think a focus on high integrity gives us a useful discipline.

# Brendan Eich (13 years ago)

Douglas Crockford wrote:

On 4/23/2012 6:41 PM, Mark S. Miller wrote:

On Mon, Apr 23, 2012 at 6:30 PM, Allen Wirfs-Brock <allen at wirfs-brock.com <mailto:allen at wirfs-brock.com>> wrote:

The point is that much of what is done on the web is not high
integrity computation. It is essential that high integrity be
possible, when it is required. But forcing all computation into the
high integrity category seems like as bad an idea as forcing all
computation to be low integrity.  I really wonder how successful JS
would have been if it had started out as a high integrity language.

Yes, I think that's a good point.

No, that is not a good point. The strange ascendance of JS can best be described as miraculous. It succeed despite its low integrity, not because of it.

Our problem is not to figure out how to make this language popular. We have somehow already managed that through amazing luck.

www.imdb.com/title/tt0076759/quotes?qt=qt0440727

I think our problem now is to disarm the array of toeguns while minimizing breakage as much as possible, and to avoid installing new toeguns. I think a focus on high integrity gives us a useful discipline.

Of course we'll never know, but I've argued something I do know: I made JS mutable by default (all objects, almost all properties safe constructor.prototype and perhaps some DOM ones) in 1995 because I knew developers would have to monkey-patch it right away. I was counting on that non-miracle to help save it.

# Douglas Crockford (13 years ago)
# Allen Wirfs-Brock (13 years ago)

On Apr 24, 2012, at 1:28 PM, Brendan Eich wrote:

Douglas Crockford wrote:

On 4/23/2012 6:41 PM, Mark S. Miller wrote:

On Mon, Apr 23, 2012 at 6:30 PM, Allen Wirfs-Brock <allen at wirfs-brock.com <mailto:allen at wirfs-brock.com>> wrote:

The point is that much of what is done on the web is not high integrity computation. It is essential that high integrity be possible, when it is required. But forcing all computation into the high integrity category seems like as bad an idea as forcing all computation to be low integrity. I really wonder how successful JS would have been if it had started out as a high integrity language.

Yes, I think that's a good point.

No, that is not a good point. The strange ascendance of JS can best be described as miraculous. It succeed despite its low integrity, not because of it.

Our problem is not to figure out how to make this language popular. We have somehow already managed that through amazing luck.

www.imdb.com/title/tt0076759/quotes?qt=qt0440727

I think our problem now is to disarm the array of toeguns while minimizing breakage as much as possible, and to avoid installing new toeguns. I think a focus on high integrity gives us a useful discipline.

Of course we'll never know, but I've argued something I do know: I made JS mutable by default (all objects, almost all properties safe constructor.prototype and perhaps some DOM ones) in 1995 because I knew developers would have to monkey-patch it right away. I was counting on that non-miracle to help save it.

Back to the original point, which was that making strict mode delete throw when applied to a non-configurable property is not significantly higher integrity than the non-strict behavior of returning false when a property can not be deleted. www.flickr.com/photos/steffmac/5733303422/lightbox

Anton reported that this delete throw was one of the two strict mode features that caused him some difficult in switching to string mode. I suggested that we might consider removing the delete throw behavior from strict mode. No body has comment on that specific idea.

# Brendan Eich (13 years ago)

Allen Wirfs-Brock wrote:

Back to the original point, which was that making strict mode delete throw when applied to a non-configurable property is not significantly higher integrity than the non-strict behavior of returning false when a property can not be deleted. www.flickr.com/photos/steffmac/5733303422/lightbox

Anton reported that this delete throw was one of the two strict mode features that caused him some difficult in switching to string mode. I suggested that we might consider removing the delete throw behavior from strict mode. No body has comment on that specific idea.

I agree! Sorry for not saying so earlier, thought it was obvious ;-).

A thrown exception doesn't necessarily stop forward progress either, with try/catch in since ES3. It tends to make empty catch boilerplate, though. I've often contended that termination-style exceptions don't scale: they're good for local protocols but bad in the large.