Whitespace (newline) following return statement

When returning an anonymous object from a function, a parse error results if the opening brace is not on the same line as the return statement; this is sensitivity to whitespace unecmascriptlike.

In the two functions below functionA() is fine, but functionB() results in "Uncaught SyntaxError: Unexpected token ':'"

It is written in the specification that a line terminator is not allowed after a return, but this strangely enforces a particular brace style for return statements that does not match what is allowed elsewhere, for example assignments.

// OK
functionA()
{
    return {
        propertyA: true,
        propertyB: true
    };
}

// Not OK
function functionB()
{
    return
    {
        propertyA: true,
        propertyB: true
    };
}

// OK
var myobject =
{
    propertyA: true,
    propertyB: true
};

It does indeed, which is why One True Brace Style is the preferred brace style in JS.

Putting brace-style religions aside ... if you look at the examples above, do you agree that it is inconsistent that a line terminator is allowed in the other scenarios, but not when returning an object-literal?

Yes, ASI is very inconsistent in terms of intuition, which is also why the recommended style is to use semicolons (and a linter that checks them for you). However, such things can’t ever be changed or they’d break websites.

(OTBS: https://en.wikipedia.org/wiki/Indent_style#Variant:1TBS.28OTBS.29 )

Where in the examples above did I not use semicolons?

Can you give a concrete example where allowing a line-terminator between the return keyword and an object literal would not be backwards compatible?

Yes, I'm aware of OTBS/1TBS, it is just one style of many, hardly the 'one true' one. Regardless, ECMAscript does not require or enforce that one particular style. However, in this scenario, where a line-terminator is not accepted between a return and an opening brace of an object-literal, the language specification is (unusually) opinionated about style.

What I am raising for discussion, is this correctable inconsistency/opinionatedness in the language specification.

I am fairly certain that the grammar/specification could be updated to allow a line-terminator between the return keyword and an object literal while maintaining backwards compatibility with all existing programs. I am raising this question to the forum to understand if this is or is not the case.

No, it wouldn’t be possible to change any aspect of the grammar here; there are programs that depend on it.

There are programs that depend on the absence of a line-terminator between the return keyword and the opening brace of an object-literal?

Can you provide a short code example of such a scenario?

Surely you cannot be suggesting that the specification cannot be changed; the title of the document is "ECMA-262, 14th edition, June 2023"

Or is this not the correct forum to suggest such changes?

All it would take is a program where that pattern appears, and code that expects the function to return undefined, and that program depends on that pattern. I expect it wouldn't take too long to find such code on github, let alone on npm, and I doubt browsers would have the risk appetite for such a change anyways.

The language almost never has breaking changes; virtually all changes are additive. Breaking changes are only possible if they're web compatible, and something as fundamental as this is almost certainly not.

A not-hard-to-imagine pattern is

function foo() {
  if (condition())
    return
  function condition() {
  }
}

Which would now be a reference error.

1 Like

Maybe not, but there are possibly programs that have an unreachable empty block after a return statement. While improbably it's valid syntax, and you can't change the meaning of valid syntax.

function functionB()
{
    return
    {
        // unreachable block
    };
}

I think this example is important too because it explains the SyntaxError in the original code. That error isn't so much about an object literal not being allowed after a return statement. Its that in that context, the brackets are being seen as a code block rather than an object literal. As a code block there's an error given the use of the comma operator between two labeled statements. Removing the comma would make the syntax valid (though the function would still return undefined).

// OK
function functionB()
{
    return
    {
        propertyA: true
        propertyB: true
    };
}

Out of context there's no distinction between a literal with a single property and a code block with a single labeled statement.

// either an object literal or a block with a labeled statement
{
    propertyA: true
}
4 Likes

Future proposals may be adding other hurdles for those who like to put the opening curly bracket on a new line. Pattern matching, for example, wishes to invent a new "match" syntax, but since "match" isn't a reserved keyword, they have to be a bit tricky about it. The current plans are as follows:

// Today this would be a syntax error.
// Because of this, they can add meaning to this syntax without
// breaking old code. A.k.a. this is what pattern-matching will likely look like.
match (val) {
  ...
}

// This is valid syntax today (we're calling a "match" function, then we have a block of code).
// Because of this, pattern-matching can't use this syntax space.
// This will always need to mean the same thing.
match (val)
{
   ...
}

In other words, as currently planned, for pattern-matching to work you must put the opening curly bracket on the same line as the "match". In general, if they ever want to invent a new control structure-like thing, and want to use a keyword for it that isn't currently reserved, this is how they'd have to do it - either that or do some ugly stuff with the new syntax.

Ideally, it wouldn't be this way and everyone could choose to place the curly brackets wherever they want, but that's just not the reality.

Good example. Some of the other mentioned scenarios could be handled by lookahead (eg. the function scenario). This one, however, is ambiguous.

This makes good sense. Returning an empty object-literal vs. undefined.

I was not aware of this proposal, this is another good point.
This would add more brace-opinionatedness, in addition to 'return' and 'throw'.

Thank you all for entertaining this idea and providing counter-examples.

1 Like