(x) => {foo: bar}

# Frankie Bagnardi (10 years ago)
let f = (x) => {foo: bar};

In the implementations I checked, this is actually allowed, but it's parsed as a label instead of what you may expect at first glance (an object).

Is there any reason this is allowed? If there's no reason other than to match function(){}, this should be a syntax error, in my opinion.

A potentially easier and wider reaching solution here would be to restrict labels in strict mode to demand a possible break/continue, else it's a syntax error. The only area I'd be concerned about compatibility is low level generated JavaScript.

Thoughts?

# Caitlin Potter (10 years ago)

In the implementations I checked, this is actually allowed, but it's

parsed as a label instead of what you may expect at first glance (an object).

For it to be a concise body, you need to change it to let f = (x) => ({foo: bar});. Otherwise, it's like a regular function body.

# Calvin Metcalf (10 years ago)

this seems like a footgun and has tripped people up in the wild twitter.com/jankrems/status/544645776518184960

# Brendan Eich (10 years ago)

See

strawman:block_vs_object_literal

This could be done, but not for ES6. Sorry I didn't push this harder, earlier.

# Domenic Denicola (10 years ago)

What do you think the chances of this are in ES7+? That is, how backward-compatible is this change? The linked strawman doesn't seem to touch on () => { foo: bar } as a back-compat hazard. Do you feel hopeful?

# Brendan Eich (10 years ago)

Domenic Denicola wrote:

What do you think the chances of this are in ES7+? That is, how backward-compatible is this change? The linked strawman doesn't seem to touch on () => { foo: bar } as a back-compat hazard.

The strawman discusses compatibility explicitly:

strawman:block_vs_object_literal#compatibility

"""

This proposal is mostly backward-compatible. In particular, the “stray label” problem whereby

javascript:foo()

migrates from URL contexts (links, |src| attribute values, the browser’s address toolbar) into script content, but not at the start of a block, continues to work. Note that such a “label” is not used by the statement or expression to which it is affixed.

Useless labels are thus allowed other than at the start of a block (immediately after the |{| that starts the block).

A block in JS today, or a block-lambda strawman:block_lambda_revival

if that extension is supported, may be prefixed by a label and actually use that label, e.g. via a |break| targeting that label. The grammar changes above support such a label-using block(-lambda).

"""

Do you feel hopeful?

Reasonably.

How often is label-after-block-opening-left-curly used and actually useful? Empirical question, where did Google codesearch go? :-/. Arrows won't change answer much, my guess, by the time ES7 is going.

# Caitlin Potter (10 years ago)

The strawman changes to the grammar are still ambiguous :(

() => {} -> noop or Object or SyntaxError? If SyntaxError, ...why?

I think hacking around this would not get rid of the footgun, but would just make it more complicated to understand the footgun, personally.

# Brendan Eich (10 years ago)

Caitlin Potter wrote:

The strawman changes to the grammar are still ambiguous :(

() => {} -> noop or Object or SyntaxError? If SyntaxError, ...why?

No, the strawman addresses this: "An empty pair of braces |{}| other than at start of /Statement/ is an /ObjectLiteral/." The grammar is unambiguous. Notice the meta-? in the first production RHS below, and the non-empty-producing nature of the second:

Block: { UnlabeledStatementFirstList? } { WellLabeledStatement StatementList? }

UnlabeledStatementFirstList: UnlabeledStatement UnlabeledStatementFirstList Statement

The final piece of the puzzle is here:

We retain the |[lookahead ∉ {{, function}]| restriction in /ExpressionStatement/. At the start of a statement, |{| can be the start of a block only, never an object literal.

I think hacking around this would not get rid of the footgun, but would just make it more complicated to understand the footgun, personally.

You mean replace the footgun with a smaller one, maybe one so small it doesn't matter. Saying that the proposal doesn't get rid of the footgun means it still remains impossible to write x => {p: x} and not get what

Frankie and others want: an arrow returning an object. But the proposal does fix that footgun.

How often do you really want an empty object instead of a block with no statements?

# Frankie Bagnardi (10 years ago)

That's good news, thanks for the strawman link. Is it correct to assume this with that proposal?

var f = (x) => (y) => {x, y};

f(1)(2) // => {x: 1, y: 2};

# Kevin Smith (10 years ago)

I think hacking around this would not get rid of the footgun, but would just make it more complicated to understand the footgun, personally.

My gut reaction is to agree - the current rule, while it takes some trivial learning, is easy to understand and communicate and is reflected well in other parts of the language. Also, additions to object literal syntax might make this more...weird:

x => { [abc](def = function() { huh() }) { blahblahblah } };

"But it's an object literal, obviously!"

# Brendan Eich (10 years ago)

Frankie Bagnardi wrote:

That's good news, thanks for the strawman link. Is it correct to assume this with that proposal?

var f = (x) => (y) => {x, y}; f(1)(2) // => {x: 1, y: 2};

Good point, the strawman does not take object literal shorthand into account and indeed parses {x, y} in an expression context as a block expression, not an object literal. More work needed, it was only straw :-P.

To clarify something Caitlin raised: the goal is to enable block expressions everywhere, and unify arrow function body on an expression nonterminal, eiminating ConciseBody (in ES6) or the two production right-parts in

ArrowFunctionExpression : ArrowFormalParameters => [lookahead ∉ { "{" }] AssignmentExpression ArrowFormalParameters => Block

from

harmony:arrow_function_syntax

# Brendan Eich (10 years ago)

Kevin Smith wrote:

I think hacking around this would not get rid of the footgun, but
would just make it more complicated to understand the footgun,
personally.

My gut reaction is to agree - the current rule, while it takes some trivial learning, is easy to understand and communicate and is reflected well in other parts of the language. Also, additions to object literal syntax might make this more...weird:

x => { [abc](def = function() { huh() }) { blahblahblah } };

"But it's an object literal, obviously!"

Yes, there's always a trade-off, some futures are foreclosed by syntax changes of this sort.

Is it worth it? Hard to say, crystal ball service not answering the phone ;-). Still, the motivation for that strawman I wrote in 2011 lives on.

# Caitlin Potter (10 years ago)

You mean replace the footgun with a smaller one, maybe one so small it

doesn't matter. Saying that the proposal doesn't get rid of the footgun means it still remains impossible to write x => {p: x} and not get what

Frankie and others want: an arrow returning an object. But the proposal does fix that footgun.

How often do you really want an empty object instead of a block with no

statements?

Okay, good point about the (lack of) ambiguity in terms of how it's interpreted, but what I'm talking about is how it looks like it should work. It looks like a function body and an object literal, and it doesn't matter which one is used more frequently, because it's going to bite people one way or the other. Rules about what sorts of statements are allowed as the first statement in a block is also going to bite people some times.

Because it bites fewer people, there will be fewer people who have dealt with it and are able to explain it, so it becomes one of those "gotchas" of the language.

This is my personal opinion, but I think the "wrap object literals in parentheses for concise bodies" is much simpler to explain to people than more complicated rules. Simple is good :>

# Kevin Smith (10 years ago)

Also, I did some analysis on this issue way back when. In the codebases that I looked at the percentage of "bound this functions" which simply returned an object literal were quite low.

(See the "%Object Literals" column)

docs.google.com/spreadsheet/ccc?key=0Aro5yQ2fa01xdENxUzBuNXczb21vUWVUX0tyVmNKTUE#gid=0, docs.google.com/spreadsheet/ccc?key=0Aro5yQ2fa01xdEJySWxhZ1VoZ0VaWTdldXp4NUtJd3c#gid=0

(from esdiscuss.org/topic/btf-measurements)

Of course, actually having arrow functions will change the situation to some degree, but the current tradeoff made sense in light of that evidence.

# Mark Volkmann (10 years ago)

In addition, I don't think Traceur supports that syntax yet. I have had to do this instead:

let f = x => { return {foo: bar}; };


/ /
\ /ark Object Computing, Inc. \ /olkmann /

# Brendan Eich (10 years ago)

Brendan Eich wrote:

Kevin Smith wrote:

I think hacking around this would not get rid of the footgun, but
would just make it more complicated to understand the footgun,
personally.

My gut reaction is to agree - the current rule, while it takes some trivial learning, is easy to understand and communicate and is reflected well in other parts of the language. Also, additions to object literal syntax might make this more...weird:

x => { [abc](def = function() { huh() }) { blahblahblah } };

"But it's an object literal, obviously!"

Yes, there's always a trade-off, some futures are foreclosed by syntax changes of this sort.

To say a bit more, your example as written above unambiguously shows an object literal body, not a block expression body. It's complex, but there's no valid parse that would interpret the stuff after => as a

block. But let's tweak it a bit:

x => { [abc](def = function() { huh() })
       { blahblahblah } };

Now ASI applies and this parses as a block or an object literal. The arrow body is ctually valid ES1!

The future-hostility of strawman:block_vs_object_literal must be traded off against the complexity burden of every-more elaborate object literal extension syntax. At some point we can stop extending object literals. Are we there yet?

If so, then the {x, y} shorthand problem Frankie raised remains. One brute-force way out is to ban leading comma expression statements in UnlabeledStatement: ExpressionStatement, which could be done. I'm still thinking about this, not super-worried.

Given ES6 arrows as drafted and implemented, and as about to be finalized, the main problem that I foresee with adding block_vs_object_literal in ES7 is how () = {} makes an empty-block body. That's why I asked

"How often do you really want an empty object instead of a block with no statements?"

a few messages back. Serious question!

# Marius Gundersen (10 years ago)

One scenario where arrow functions are likely to return objects is in the map function of arrays and the pipe function for streams. For example:

[1,2,3] .map(x => {value: x, double:2*x}) .filter(x => x.double < 5)

Marius Gundersen

On 5 Jan 2015 21:16, "Kevin Smith" <zenparsing at gmail.com> wrote:

Also, I did some analysis on this issue way back when. In the codebases

that I looked at the percentage of "bound this functions" which simply returned an object literal were quite low.

(See the "%Object Literals" column)

docs.google.com/spreadsheet/ccc?key=0Aro5yQ2fa01xdENxUzBuNXczb21vUWVUX0tyVmNKTUE#gid=0

docs.google.com/spreadsheet/ccc?key=0Aro5yQ2fa01xdEJySWxhZ1VoZ0VaWTdldXp4NUtJd3c#gid=0

(from esdiscuss.org/topic/btf-measurements)

Of course, actually having arrow functions will change the situation to

some degree, but the current tradeoff made sense in light of that evidence.

On Mon, Jan 5, 2015 at 3:06 PM, Brendan Eich <brendan at mozilla.org> wrote:

Kevin Smith wrote:

I think hacking around this would not get rid of the footgun, but
would just make it more complicated to understand the footgun,
personally.

My gut reaction is to agree - the current rule, while it takes some

trivial learning, is easy to understand and communicate and is reflected well in other parts of the language. Also, additions to object literal syntax might make this more...weird:

x => { [abc](def = function() { huh() }) { blahblahblah } };

"But it's an object literal, obviously!"

Yes, there's always a trade-off, some futures are foreclosed by syntax

changes of this sort.

Is it worth it? Hard to say, crystal ball service not answering the

phone ;-). Still, the motivation for that strawman I wrote in 2011 lives on.

# Brendan Eich (10 years ago)

Caitlin Potter wrote:

You mean replace the footgun with a smaller one, maybe one so small it doesn't matter. Saying that the proposal doesn't get rid of the footgun means it still remains impossible to write x => {p: x} and not get what Frankie and others want: an arrow returning an object. But the proposal does fix that footgun.

How often do you really want an empty object instead of a block with no statements?

Okay, good point about the (lack of) ambiguity in terms of how it's interpreted, but what I'm talking about is how it looks like it should work. It looks like a function body and an object literal, and it doesn't matter which one is used more frequently, because it's going to bite people one way or the other.

True. Can't share { as I did in JS and avoid this. Ship sailed long ago.

Rules about what sorts of statements are allowed as the first statement in a block is also going to bite people some times.

Probably not useless labels at the front. Seriously, the change to allow labels only at top level or else in front of any label-using statement (and no other) is almost perfectly backward compatible. Stray and unused labels are latent bugs, even if just minor left-over or misplace noise.

Because it bites fewer people, there will be fewer people who have dealt with it and are able to explain it, so it becomes one of those "gotchas" of the language.

Yes, a smaller footgun -- not the same one that started this thread. I agree it's vexing to have a footgun left, but if it differs in quality and frequency of misfires, maybe it's worthwhile. Hard to assess.

I also agree KISS favors what we all agreed to do, which was (a) take arrows into ES6; (b) not pursue block_vs_object_literal after I wrote it up. But we could revisit (b) and that seems worth some es-discuss overhead.

This is my personal opinion, but I think the "wrap object literals in parentheses for concise bodies" is much simpler to explain to people than more complicated rules. Simple is good :>

Your advice is good as far as it goes; it seems not to reach enough people to avoid a real-world speedbump, from the root message in this thread.

If the speedbump were caught at compile-time, no big. That it results in runtime behavior differing from the DWIM intent of the programmer means latent bugs. Perhaps JSLint, ESHint, etc., will be updated to catch the bad thing in the field, and that will suffice.

# Mark Volkmann (10 years ago)

My apologies. I meant to say that Traceur doesn't support returning a literal object from an arrow function with syntax like this:

let f = x => ({foo: bar});

However, I just tested it again and it works fine. I could swear this didn't work a few months ago. Maybe it was fixed recently. I'm happy!

# Brendan Eich (10 years ago)

Mark Volkmann wrote:

My apologies. I meant to say that Traceur doesn't support returning a literal object from an arrow function with syntax like this:

let f = x => ({foo: bar});

However, I just tested it again and it works fine. I could swear this didn't work a few months ago. Maybe it was fixed recently. I'm happy!

Cool -- you are supporting Caitlin's thesis that we can pedagogue around the footgun. I hope so.

Still leaves strawman:block_vs_object_literal as an option for ES7. Comments welcome.

# Jasper St. Pierre (10 years ago)

Unless

x => {foo: bar}

and

x => {}

both parse as object literals, I'm against your proposal. Either un-paren'd braces are consistently a block, or they're consistently an object literal. Python has had major pains with "i before e except after c" rules to make the language nicer to use, and it's easier to tell people "always add the parens".

A third option is to make x => {foo: bar} a syntax error to steer people

away from an accidental footgun, while still making {} a block, and keeping the consistency of "parens around object literals".

# Brendan Eich (10 years ago)

Jasper St. Pierre wrote:

Unless

x => {foo: bar}

and

x => {}

both parse as object literals, I'm against your proposal. Either un-paren'd braces are consistently a block, or they're consistently an object literal. Python has had major pains with "i before e except after c" rules to make the language nicer to use, and it's easier to tell people "always add the parens".

Fair.

A third option is to make x => {foo: bar} a syntax error to steer people away from an accidental footgun, while still making {} a block, and keeping the consistency of "parens around object literals".

Just about too late for ES6, though. Eep!

# Gary Guo (10 years ago)

Strongly negative against the proposal. I believe that charisma of a language comes from its simplicity. The proposal seems to add too many syntax rules to ES. btw it is not easy to implement such a syntax into practice. I'm afraid there will be more syntax refinement, which actually make the parser to scan source code twice (or adjust the AST afterward, but currently traceur reparse the code when refine the destructuring assignment). I don't feel it worthwhile.

Though I am strongly negative, but there actually is such an implementation. The REPL of node will parse {a:1} as object literal while {a:1;} as block.

# Alex Kocharin (10 years ago)

An HTML attachment was scrubbed... URL: esdiscuss/attachments/20150106/66238b7a/attachment

# Ron Buckton (10 years ago)

For better or worse, C# avoids this ambiguity through the use of the new operator:

f = x => y => new { x, y };

Of course, C# does not support creating an object literal (nee. "anonymous type") without new, but using new here would be generally unambiguous in ES7+. Although its legal to write new {} in ES today, it currently results in a runtime exception.

Ron

Sent from my Windows Phone

# Isiah Meadows (10 years ago)

Once again...forgot to change the subject. (I get the digest...can't you tell?) sigh

# Isiah Meadows (10 years ago)

From: Alex Kocharin <alex at kocharin.ru> To: Gary Guo <nbdd0121 at hotmail.com>, "brendan at mozilla.org" <brendan at mozilla.org> Cc: "es-discuss at mozilla.org" <es-discuss at mozilla.org> Date: Tue, 06 Jan 2015 06:59:52 +0300 Subject: Re: (x) => {foo: bar}

06.01.2015, 06:38, "Gary Guo" <nbdd0121 at hotmail.com>:

Though I am strongly negative, but there actually is such an implementation. The REPL of node will parse {a:1} as object literal while {a:1;} as block.

Node.js REPL wraps all the statements in parentheses. Therefore {a:1;} becomes ({a:1;}) which is a syntax error.

Not in my REPL (node 0.10.33).

$ node
> {a:1;}

1
> {a:1}
{ a: 1 }

What the Node.js REPL effectively appears to do, AFAICT, is some sort of evented try-catch. Though, @Gary, I agree 100% with what you said about being very against it. It would require a lot more context to figure out if something returns an object, as {a, b, c} is technically both a valid block and object (using shorthand properties). The problems would then become non-obvious and difficult to diagnose in practice.

# Gary Guo (10 years ago)

Nope. {a:1;} will work in REPL of Node.js. In source code of repl.js, it will wrap input with parentheses first, and if there is a syntax error, it then evaluate the code without parentheses. You can test {a:1} and {a:1;}, both of them works; the former one returns {a:1} while the latter one returns 1.

From: alex at kocharin.ru To: nbdd0121 at hotmail.com; brendan at mozilla.org CC: es-discuss at mozilla.org Subject: Re: (x) => {foo: bar}

Date: Tue, 6 Jan 2015 06:59:52 +0300

06.01.2015, 06:38, "Gary Guo" <nbdd0121 at hotmail.com>: Though I am strongly negative, but there actually is such an implementation. The REPL of node will parse {a:1} as object literal while {a:1;} as block. Node.js REPL wraps all the statements in parentheses. Therefore {a:1;} becomes ({a:1;}) which is a syntax error.

# Dean Landolt (10 years ago)

On Mon, Jan 5, 2015 at 6:06 PM, Brendan Eich <brendan at mozilla.org> wrote:

Jasper St. Pierre wrote:

Unless

x => {foo: bar}

and

x => {}

both parse as object literals, I'm against your proposal. Either un-paren'd braces are consistently a block, or they're consistently an object literal. Python has had major pains with "i before e except after c" rules to make the language nicer to use, and it's easier to tell people "always add the parens".

Fair.

A third option is to make x => {foo: bar} a syntax error to steer people

away from an accidental footgun, while still making {} a block, and keeping the consistency of "parens around object literals".

Just about too late for ES6, though. Eep!

Is it though? ISTM there's consensus that this is a footgun -- isn't that a kind of spec bug? If it's too late to properly vet a change which narrowly excludes from arrow bodies any LabeledStatement that isn't a WellLabeledStatement, would it be feasible to simply exclude any LabeledStatement for now? I doubt there's much code in the wild that would be affected by this change -- certainly not yet. That'd buy plenty of time to add back proper support for WellLabeledStatement arrow bodies in es7.

Implicitly returning object literals would still require paren wrapping, of course -- and in light of the empty object / empty block ambiguity this seems inevitable. And we'll get a fail-fast compile error for the common case (non-empty objects) to would help educate and remind us all of the distinction.

# Rick Waldron (10 years ago)

On Tue Jan 06 2015 at 2:18:47 AM Isiah Meadows <impinball at gmail.com> wrote:

From: Alex Kocharin <alex at kocharin.ru> To: Gary Guo <nbdd0121 at hotmail.com>, "brendan at mozilla.org" < brendan at mozilla.org> Cc: "es-discuss at mozilla.org" <es-discuss at mozilla.org> Date: Tue, 06 Jan 2015 06:59:52 +0300 Subject: Re: (x) => {foo: bar}

06.01.2015, 06:38, "Gary Guo" <nbdd0121 at hotmail.com>:

Though I am strongly negative, but there actually is such an implementation. The REPL of node will parse {a:1} as object literal while {a:1;} as block.

Node.js REPL wraps all the statements in parentheses. Therefore {a:1;} becomes ({a:1;}) which is a syntax error.

Not in my REPL (node 0.10.33).

$ node
> {a:1;}
1
> {a:1}
{ a: 1 }

What the Node.js REPL effectively appears to do, AFAICT, is some sort of evented try-catch.

No, that's not what it does. Alex was close, but not exactly right. The REPL will test input and wrap if necessary: joyent/node/blob/master/lib/repl.js#L266

# Brendan Eich (10 years ago)

Dean Landolt wrote:

ISTM there's consensus that this is a footgun -- isn't that a kind of spec bug?

No, it's a trade-off, and recent comments in this thread argue against complicating the grammar and real-world parsers, and in favor of teaching people to parenthesize. Nowhere near consensus on what to do about the trade-off. Lots of footguns, more than feet, out there in design space.

# Brendan Eich (10 years ago)

Sorry, sent too soon.

Dean Landolt wrote:

If it's too late to properly vet a change which narrowly excludes from arrow bodies any LabeledStatement that isn't a WellLabeledStatement, would it be feasible to simply exclude any LabeledStatement for now? I doubt there's much code in the wild that would be affected by this change -- certainly not yet. That'd buy plenty of time to add back proper support for WellLabeledStatement arrow bodies in es7.

The ES6 grammar has not been refactored per my old strawman. It has no WellLabeledStatement non-terminal.

For ES6, we would need another production parameter to FunctionBody, FunctionStatementList, and StatementList (at least) by which to restrict a ConciseBody : { FunctionBody } such that the FunctionBody : FunctionStatementList (via FunctionStatementList : StatementList[opt], StatementList StatementListItem, etc.) doesn't start with a LabelledStatement.

Cc'ing Allen and Waldemar for their thoughts.

# Marius Gundersen (10 years ago)

I don't see how wellLabeledStatement will protect against object literals with shorthand properties, like (x, y, z) => {x, y, z}.

The solution to the block vs object problem today is to wrap the object in parenthesis, but not the block. The only alternative that is easy for humans to understand and not ambiguous for machines is to wrap or prefix the block, but not the object, for example with do:

x => do { let a = 5; return a*x; }

AFAIK do expressions are not in ES6, but might be in ES7.

Marius Gundersen

# Isiah Meadows (10 years ago)

Okay: is this a valid statement/expression? I didn't think so, but I may be wrong.

({ foo(); bar(); })
# Brendan Eich (10 years ago)

Marius Gundersen wrote:

I don't see how wellLabeledStatement will protect against object literals with shorthand properties, like (x, y, z) => {x, y, z}.

The solution to the block vs object problem today is to wrap the object in parenthesis, but not the block. The only alternative that is easy for humans to understand and not ambiguous for machines is to wrap or prefix the block, but not the object, for example with do:

x => do { let a = 5; return a*x; }

AFAIK do expressions are not in ES6, but might be in ES7.

do-expressions are in good shape for ES7, stage 2 or better IIRC. I can't find a record of this at the moment, but perhaps arossberg has a link.

# Dean Landolt (10 years ago)

On Tue, Jan 6, 2015 at 3:57 PM, Marius Gundersen <gundersen at gmail.com>

wrote:

I don't see how wellLabeledStatement will protect against object literals with shorthand properties, like (x, y, z) => {x, y, z}.

It would "protect" against them by disallowing them without the paren wrapping. A fail-fast SyntaxError beats the hell out of trying to diagnose an almost imperceptible runtime bug.

The solution to the block vs object problem today is to wrap the object in parenthesis, but not the block. The only alternative that is easy for humans to understand and not ambiguous for machines is to wrap or prefix the block, but not the object, for example with do:

x => do { let a = 5; return a*x; }

AFAIK do expressions are not in ES6, but might be in ES7.

I don't follow -- this isn't a labeled statement. How would it be any different from this?

x => { let a = 5; return a*x; }

AFAIK nobody's proposed forbidding this form. How would do-expressions help here? Sure, IIUC do-expressions would be a good solution for labeled blocks, when they're available. But by es7 there's also plenty of time to refactor the spec to allow some variant of /be's proposed WellLabeledStatement grammar, which would allow well-formed labeled statements w/o the do prefix.

Just to reiterate, I'm arguing that paren-wrapping should *still *be required around object literal arrow bodies, now and forever. Anything else would be impossibly confusing. But I can't see a reason to allow an (accidentally) unwrapped object literal to parse. If it's not a "well-labeled statement", it's surely a mistake.

Marius Gundersen

# Brendan Eich (10 years ago)

Dean Landolt wrote:

On Tue, Jan 6, 2015 at 3:57 PM, Marius Gundersen <gundersen at gmail.com <mailto:gundersen at gmail.com>> wrote:

I don't see how wellLabeledStatement will protect against object
literals with shorthand properties, like (x, y, z) => {x, y, z}.

It would "protect" against them by disallowing them without the paren wrapping. A fail-fast SyntaxError beats the hell out of trying to diagnose an almost imperceptible runtime bug.

No, Marius has a point here: there's no LABEL: before anything in {x, y, z}.

# Rick Waldron (10 years ago)

On Tue Jan 06 2015 at 4:53:05 PM Isiah Meadows <impinball at gmail.com> wrote:

Okay: is this a valid statement/expression? I didn't think so, but I may be wrong.

({ foo(); bar(); })

That's not valid for any grammar in up to and including ES6.

To make it valid, pick one, but not both:

  • Remove the parens and it's valid block syntax.
  • Remove everything inside the curlies, except for the word foo and it's valid object literal syntax, containing an identifier reference for some binding named foo (property short hand).
# monolithed (10 years ago)

Can anyone explain what to expect as a result of the following expression?

var fn = () => ({ a, b } = { a: 0, b: 1 });

var fn = function () { var a = 0, b = 1;

return { a: a, b: b };

};

or

  1. (traceur-compiler)

var fn = function () { var tmp;

return (tmp = {a: 0, b: 1}, a = tmp.a, b = tmp.b, tmp);

};

There're global variables in the second case

# Kevin Smith (10 years ago)

var fn = () => ({ a, b } = { a: 0, b: 1 });

The expression ({ a, b } = { a: 0, b: 1 }) is a destructuring assignment. If there are lexical bindings for a and b it will assign to those. Otherwise, in strict mode it will fail with a ReferenceError. In sloppy mode, it will assign to the global.

traceur is correct.

# Gary Guo (10 years ago)

I found that even without shorthand, the object literal can still be ambiguous with block.

  }}
shall it be interpreted as()=>({  method(){    // method body  }})

or 
()=>{  method();  {    // block statement  }}```

This is certainly an ambiguity that cannot be resolved by any transformation, or refinement of syntax. (so does the shorthand {x,y,z})
# Allen Wirfs-Brock (10 years ago)

On Jan 6, 2015, at 5:34 PM, Gary Guo wrote:

I found that even without shorthand, the object literal can still be ambiguous with block.

Yes, but not in the context of a ConciseBody of an ArrowFunction.

The grammar for ConciseBody (people.mozilla.org/~jorendorff/es6-draft.html#sec-arrow-function-definitions ) ensures that there is no ambiguity. If a ConciseBody starts with a { then it must parse as either a well-formed bracketed FunctionBody or as a syntax error.

There is no guessing. { means statements follow rather than an expression.

# Brendan Eich (10 years ago)

Allen Wirfs-Brock wrote:

On Jan 6, 2015, at 5:34 PM, Gary Guo wrote:

I found that even without shorthand, the object literal can still be ambiguous with block.

Yes, but not in the context of a ConciseBody of an ArrowFunction.

The grammar for ConciseBody (people.mozilla.org/~jorendorff/es6-draft.html#sec-arrow-function-definitions, people.mozilla.org/~jorendorff/es6-draft.html#sec-arrow-function-definitions ) ensures that there is no ambiguity. If a ConciseBody starts with a { then it must parse as either a well-formed bracketed FunctionBody or as a syntax error.

There is no guessing. { means statements follow rather than an expression.

Indeed. Perhaps Gary meant less formal ambiguity, as Caitlin did earlier in thread -- in which case we could future-proof or perhaps just help people by proscribing { L: 42 } from being parsed as a ConciseBody. I'm curious to know what you think about this idea. It seems best done with parametric productions, but I haven't worked it out yet.

# Allen Wirfs-Brock (10 years ago)

On Jan 7, 2015, at 1:23 PM, Brendan Eich wrote:

Allen Wirfs-Brock wrote:

On Jan 6, 2015, at 5:34 PM, Gary Guo wrote:

I found that even without shorthand, the object literal can still be ambiguous with block.

Yes, but not in the context of a ConciseBody of an ArrowFunction.

The grammar for ConciseBody (people.mozilla.org/~jorendorff/es6-draft.html#sec-arrow-function-definitions, people.mozilla.org/~jorendorff/es6-draft.html#sec-arrow-function-definitions ) ensures that there is no ambiguity. If a ConciseBody starts with a { then it must parse as either a well-formed bracketed FunctionBody or as a syntax error.

There is no guessing. { means statements follow rather than an expression.

Indeed. Perhaps Gary meant less formal ambiguity, as Caitlin did earlier in thread -- in which case we could future-proof or perhaps just help people by proscribing { L: 42 } from being parsed as a ConciseBody. I'm curious to know what you think about this idea. It seems best done with parametric productions, but I haven't worked it out yet.

Certainly is plausible. I suspect there might be a couple places in the ES grammar where we could replace lookahead restrictions with parameterization. I'm less sure whether there is a reason to prefer one over the other.

ObjectLiteral is already doing double duty covering ObjectAssignmentPattern. so this would be even more complexity in this area of the grammar.

Finally, I'm sort of on the side that this may not be so good for programmers. The rule, "if it starts with a { its a function body" is simple to teach and remember. Adding "except if the first thing is a labeled expression statement" (or whatever) is more difficult to explain and remember. More likely then not, all that many programmers would take away is "there are some special cases here that I don't really remember so I need to be really careful". I'm not sure that is an improvement over the status quo.

# Brendan Eich (10 years ago)

Allen Wirfs-Brock wrote:

ObjectLiteral is already doing double duty covering ObjectAssignmentPattern. so this would be even more complexity in this area of the grammar.

Yeah, the complexity counter-argument is strong.

Finally, I'm sort of on the side that this may not be so good for programmers. The rule, "if it starts with a { its a function body" is simple to teach and remember. Adding "except if the first thing is a labeled expression statement" (or whatever) is more difficult to explain and remember. More likely then not, all that many programmers would take away is "there are some special cases here that I don't really remember so I need to be really careful". I'm not sure that is an improvement over the status quo.

Me either, as noted up-thread. The option to prohibit a label at start of body wouldn't commit us to doing block_vs_object_literal, though. It would just carve out the future option. Still, no point in that work if we think we will never take the option.

# Gary Guo (10 years ago)

Even when we want to throw early errors for object-literal-like block, I consider my argument still valid. ()=>{ method() { }}Should we throw an early error? Of course not, but it might be a potential error; out task is not to warn on object-literal-like block; instead, maybe simply we can just disallow improperly labelled statement in arrow function body.

# Herby Vojčík (10 years ago)

Brendan Eich wrote:

Mark Volkmann wrote:

My apologies. I meant to say that Traceur doesn't support returning a literal object from an arrow function with syntax like this:

let f = x => ({foo: bar});

However, I just tested it again and it works fine. I could swear this didn't work a few months ago. Maybe it was fixed recently. I'm happy!

Cool -- you are supporting Caitlin's thesis that we can pedagogue around the footgun. I hope so.

Still leaves strawman:block_vs_object_literal as an option for ES7. Comments welcome.

A crazy idea:

(a, b) { body } (a, b) => expr /* always expr context */

the only problem I quickly see is to distiguish (a) { body }, but IMHO there is the same lookahead need for distiguishing (a) => something today.

# Herby Vojčík (10 years ago)

Marius Gundersen wrote:

I don't see how wellLabeledStatement will protect against object literals with shorthand properties, like (x, y, z) => {x, y, z}.

The solution to the block vs object problem today is to wrap the object in parenthesis, but not the block. The only alternative that is easy for humans to understand and not ambiguous for machines is to wrap or prefix the block, but not the object, for example with do:

x => do { let a = 5; return a*x; }

Yeah, this is good.

Even if do expression won't get in, if one could clearly tell the intent (block vs. expression), it would make things easier to work with.

=> expr / => do block is less ambiguous then => expr / [nothing] block I

posted earlier.