Another paren-free gotcha

# Waldemar Horwat (6 years ago)

Thinking about the implications of paren-free, I see additional potential trouble spots in addition to the one I mentioned in the meeting yesterday:

Start with ES5 code:

if (a + b) (x.y)() z++

Now (erroneously) convert it to paren-free:

if a + b (x.y)() z++

This doesn't give a syntax error; it silently changes the meaning of the program.

Another hidden pitfall of the paren-free experience is illustrated by the expression refactoring to add parentheses:

Start with ES5 code:

if (a + b/g > f) f = a + b/g

Convert it to paren-free:

if a + b/g > f {f = a + b/g}

So far so good; it works. However, later someone discovers that the code had a logic error, the fix to which is to divide the sum a+b by c instead of dividing only b by c. So he fixes the code to:

if (a + b)/g > f {f = (a + b)/g}

Oops. Now the / starts a regexp. There is an extra closing brace which will simply close the enclosing scope early, so a syntax error likely won't appear for a while.

 Waldemar
# Douglas Crockford (6 years ago)

On 11:59 AM, Waldemar Horwat wrote:

Thinking about the implications of paren-free, I see additional potential trouble spots in addition to the one I mentioned in the meeting yesterday:

Start with ES5 code:

if (a + b) (x.y)() z++

Now (erroneously) convert it to paren-free:

if a + b (x.y)() z++

This doesn't give a syntax error; it silently changes the meaning of the program.

Another hidden pitfall of the paren-free experience is illustrated by the expression refactoring to add parentheses:

Start with ES5 code:

if (a + b/g > f) f = a + b/g

Convert it to paren-free:

if a + b/g > f {f = a + b/g}

So far so good; it works. However, later someone discovers that the code had a logic error, the fix to which is to divide the sum a+b by c instead of dividing only b by c. So he fixes the code to:

if (a + b)/g > f {f = (a + b)/g}

Oops. Now the / starts a regexp. There is an extra closing brace which will simply close the enclosing scope early, so a syntax error likely won't appear for a while.

These are indeed concerns. But paren-free is still worthwhile. My view is in that in a statement like

 if (a + b/g > f) {f = a + b/g;}

that either the parens around the condition are optional, or the braces around the consequence are optional, but not both (with allowance for 'if else'). My argument with Thompson and Ritchie is that they chose which pair was required, and they picked the wrong pair.

# Peter van der Zee (6 years ago)

On Thu, Sep 29, 2011 at 12:38 AM, Douglas Crockford <douglas at crockford.com> wrote:

On 11:59 AM, Waldemar Horwat wrote:

Thinking about the implications of paren-free, I see additional potential trouble spots in addition to the one I mentioned in the meeting yesterday:

These kind of potential confusions raise a red flag for me. Goes in line with the ASI discussion, or the more current array hole discussion. People are going to cause errors using this syntax, especially when editing existing code. And when they do, they won't have a clue why. At least not at first. I think Waldemar nailed that with his demonstrations.

# Allen Wirfs-Brock (6 years ago)

perhaps the algol/pascal/PL/I /etc use of a "then" keywords wasn't such a bud idea after all...

# Brendan Eich (6 years ago)

On Sep 28, 2011, at 4:02 PM, Peter van der Zee wrote:

On Thu, Sep 29, 2011 at 12:38 AM, Douglas Crockford <douglas at crockford.com> wrote:

On 11:59 AM, Waldemar Horwat wrote:

Thinking about the implications of paren-free, I see additional potential trouble spots in addition to the one I mentioned in the meeting yesterday:

These kind of potential confusions raise a red flag for me.

Not sure about. Waldemar's examples can bite plain old expression-statement refactoring too. Is this really a fatal flaw of paren-free, or more a problem with C-family expression-statement syntax?

If ASI is the culprit to focus on, I can work harder on ASI in relation to paren-free. I do not want to hack on paren-free by itself. It's quite simple and not in need of "patching".

# Brendan Eich (6 years ago)

On Sep 28, 2011, at 4:02 PM, Peter van der Zee wrote:

On Thu, Sep 29, 2011 at 12:38 AM, Douglas Crockford <douglas at crockford.com> wrote:

On 11:59 AM, Waldemar Horwat wrote:

Thinking about the implications of paren-free, I see additional potential trouble spots in addition to the one I mentioned in the meeting yesterday:

These kind of potential confusions raise a red flag for me.

Not sure about. Waldemar's examples can bite plain old expression-statement refactoring too. Is this really a fatal flaw of paren-free, or more a problem with C-family expression-statement syntax?

If ASI is the culprit to focus on, I can work harder on ASI in relation to paren-free. I do not want to hack on paren-free by itself. It's quite simple and not in need of "patching".

# Brendan Eich (6 years ago)

On Sep 28, 2011, at 5:53 PM, Brendan Eich wrote:

Not sure about. Waldemar's examples can bite plain old expression-statement refactoring too. Is this really a fatal flaw of paren-free, or more a problem with C-family expression-statement syntax?

Combined with regexps, of course, in the last case (leaving ASI out).

If ASI is the culprit to focus on, I can work harder on ASI in relation to paren-free. I do not want to hack on paren-free by itself. It's quite simple and not in need of "patching".

My approach would be to make newlines more significant, not less.

# Quildreen Motta (6 years ago)

** On 28/09/11 18:11, Waldemar Horwat wrote:

Thinking about the implications of paren-free, I see additional potential trouble spots in addition to the one I mentioned in the meeting yesterday:

Start with ES5 code:

if (a + b) (x.y)() z++

Now (erroneously) convert it to paren-free:

if a + b (x.y)() z++

This doesn't give a syntax error; it silently changes the meaning of the program.

I'm not sure how this is much different from the rules you have now with ASI, though if this were such a problem, a block statement could be required with paren-free conditions that aren't followed by a block sub-statement, or a keyword prefixed one. Though, again, I don't think it would make much sense — as the current syntax is pretty consistent with what's expected from ASI rules.

Oh, yes, people often blame ASI because it's unintuitive and blah blah blah. I think it's more a problem of people expecting JS to be parsed as any other C-language family (more close to Java, perhaps?), whereas semicolons are treated in a manner almost close to Python, except for the fact you have tokens for implicit statement continuations instead of a single escape character for explicit statement continuation.

Another hidden pitfall of the paren-free experience is illustrated by the expression refactoring to add parentheses:

Start with ES5 code:

if (a + b/g > f) f = a + b/g

Convert it to paren-free:

if a + b/g > f {f = a + b/g}

So far so good; it works. However, later someone discovers that the code had a logic error, the fix to which is to divide the sum a+b by c instead of dividing only b by c. So he fixes the code to:

if (a + b)/g > f {f = (a + b)/g}

Oops. Now the / starts a regexp. There is an extra closing brace which will simply close the enclosing scope early, so a syntax error likely won't appear for a while.

This is more of a real problem, with which I am concerned with =/

# Peter van der Zee (6 years ago)

On Thu, Sep 29, 2011 at 3:43 AM, Quildreen Motta <quildreen at gmail.com> wrote:

I'm not sure how this is much different from the rules you have now with ASI, though if this were such a problem, a block statement could be required

I'm trying to make sure we don't add another feature that we'll later describe as "yeah, wish we could take that out, but we can't, that ship has sailed". This ship hasn't sailed yet and if it does, I'd like it to be as clean as possible.

On Thu, Sep 29, 2011 at 3:01 AM, Brendan Eich <brendan at mozilla.com> wrote:

If ASI is the culprit to focus on, I can work harder on ASI in relation to paren-free. I do not want to hack on paren-free by itself. It's quite simple and not in need of "patching".

My approach would be to make newlines more significant, not less.

What you could do here is require paren-less headers to be single lined, on the same line as the if keyword, and require a newline between the paren-less header and the body. Such newline would signify the end of the statement header, much like ASI ("API"? ;). And if you want to use a block, you may put the first curly of the block on the same line as the paren-less header (or next line if you prefer K&R anyways). I'm not so sure if that would fix any of the raised objections though. You'd also be introducing more restrictions in the grammar (afaik you weren't very fond of these) and introduce another ASI-like scheme into the language.

I worry a bit about legibility (but have nothing to back that up with).

# Brendan Eich (6 years ago)

On Sep 29, 2011, at 9:06 AM, Peter van der Zee wrote:

What you could do here is require paren-less headers to be single lined, on the same line as the if keyword, and require a newline between the paren-less header and the body. Such newline would signify the end of the statement header, much like ASI ("API"? ;). And if you want to use a block, you may put the first curly of the block on the same line as the paren-less header (or next line if you prefer K&R anyways). I'm not so sure if that would fix any of the raised objections though.

It would fix the first:

if a + b (x.y)() z++

because of no { on same line as the head, but it would not fix the second case Waldemar showed:

if (a + b)/g > f {f = (a + b)/g}

This case is a paren-full if head followed by an unbraced body, a useless regexp expression statement. It's valid ES5. The reason this involves paren-free is that Waldemar showed how refactoring from paren-full to paren-free mixes with division and a regexp literal to make this paren-full but undesired outcome.

The ability to write useless expression statements in JS (and C) is a bug.

# Quildreen Motta (6 years ago)

2011/9/29 Peter van der Zee <ecma at qfox.nl>

On Thu, Sep 29, 2011 at 3:43 AM, Quildreen Motta <quildreen at gmail.com> wrote:

I'm not sure how this is much different from the rules you have now with ASI, though if this were such a problem, a block statement could be required

I'm trying to make sure we don't add another feature that we'll later describe as "yeah, wish we could take that out, but we can't, that ship has sailed". This ship hasn't sailed yet and if it does, I'd like it to be as clean as possible.

Yeah, perfecting things is something I can appreciate. My point, however, was that I couldn't see a problem with Waldemar's first example since they are consistent with the current ECMAScript semantics (ASI). I personally find languages with few divergent semantic constructs better because you have less to learn and worry about when coding.

# Dean Landolt (6 years ago)

On Thu, Sep 29, 2011 at 11:09 AM, Brendan Eich <brendan at mozilla.com> wrote:

On Sep 29, 2011, at 9:06 AM, Peter van der Zee wrote:

What you could do here is require paren-less headers to be single lined, on the same line as the if keyword, and require a newline between the paren-less header and the body. Such newline would signify the end of the statement header, much like ASI ("API"? ;). And if you want to use a block, you may put the first curly of the block on the same line as the paren-less header (or next line if you prefer K&R anyways). I'm not so sure if that would fix any of the raised objections though.

It would fix the first:

if a + b (x.y)() z++

because of no { on same line as the head, but it would not fix the second case Waldemar showed:

if (a + b)/g > f {f = (a + b)/g}

This case is a paren-full if head followed by an unbraced body, a useless regexp expression statement. It's valid ES5.

Not on its own it's not -- it may close a block but what about the rest of that block? Your curlies won't balance and you've got a syntax error. Sure, you could choose to paper over it by indiscriminately adding closing braces until you parse but this isn't a completely silent failure.

The reason this involves paren-free is that Waldemar showed how refactoring from paren-full to paren-free mixes with division and a regexp literal to make this paren-full but undesired outcome.

The ability to write useless expression statements in JS (and C) is a bug.

Isn't "use strict" a useless expression statement? But that's about the only useful use of useless expressions I can think of.

# Brendan Eich (6 years ago)

On Sep 29, 2011, at 10:16 PM, Dean Landolt wrote:

because of no { on same line as the head, but it would not fix the second case Waldemar showed:

if (a + b)/g > f {f = (a + b)/g}

This case is a paren-full if head followed by an unbraced body, a useless regexp expression statement. It's valid ES5.

Not on its own it's not -- it may close a block but what about the rest of that block? Your curlies won't balance and you've got a syntax error.

Yes, but if there's no left context with an unclosed open curly, you get the error immediately. Waldemar's scenario, as he implied, was that there were unclosed {s to the left, which would make the possibly-much-farther-along extra } error obscure.

Isn't "use strict" a useless expression statement? But that's about the only useful use of useless expressions I can think of.

It is not, by definition, in ES5. That makes it tricky, but once you opt into Harmony, ES6 or higher let's say (I'm cheeky about using 6), then it is again useless. Harmony is built on ES5 strict. No more string literal pragmas, they bite back. And (not yet anyway) no more stricter strict modes.