Isiah Meadows (2015-07-13T23:56:36.000Z)
On Mon, Jul 13, 2015 at 7:53 PM, Isiah Meadows <impinball at gmail.com> wrote:
>
> To be perfectly honest, though, I'm not entirely sure the specifics of the do-expression proposal, since Google is failing me here (can't find a thing giving more detail than this mailing list). And as for what my proposal here is, I forgot to mention that expression statements would be explicitly prohibited as the body of a do-expression.
>
> As for yours, I like it too, except if we keep adding all these extra parentheses, we might as well make JavaScript into a Lisp...(well, except LispyScript kinda has...) ;)
>
> In all seriousness, I like your idea as well, but the parsing would have to take into account a similar distinction between expressions and other statements. And that problem with objects vs blocks would result in a similar situation we previously ran into with the same ambiguity (in reverse) in arrow function syntax. The other issue is that your proposal, because of that ambiguity, would likely bring a break in backwards compatibility, one that is definitely not worth it:
>
> ```js
> // Is this a block or object literal?
> let foo = ({ bar: 1 });
> ```
>
> On Mon, Jul 13, 2015 at 7:33 PM, Mark S. Miller <erights at google.com> wrote:
>>
>> Interesting. Got me thinking. Here's an alternate proposal I'll call "do expressions without the 'do'."
>>
>> At <https://people.mozilla.org/~jorendorff/es6-draft.html#sec-expression-statement> we have the syntax of the expression statement. Ignoring sloppy "let" nonsense, this says that an expression statement cannot begin with "{", "function", or "class".
>>
>> At <https://people.mozilla.org/~jorendorff/es6-draft.html#sec-ecmascript-language-statements-and-declarations> are the legal ES6 statements. Note that most of these begin with a keyword that cannot possibly be legal at the beginning of an expression. Therefore, adding all these initial-statement-keywords to the list of things that cannot begin an expression statement would break nothing. They already cannot begin an expression statement.
>>
>> With the expression statement prohibition in place, now we can allow all these forms to be expressions. As with "{", "function", or "class", if you want to state such an expression in expression-statement position, surround it with parens.
>>
>> Because all these new forms will look bizarre and confusing, at least at first, let's say these always need surrounding parens to be expressions. I think that would help minimize confusion.
>>
>> If we do this, the oddest duck is "{", since it begins an object literal expression. This proposal gives us no straightforward way to express an block expression. "function" and "class" are less odd, since their existing expression forms mean what you almost might expect by this new rule -- even though they are initial-declaration-keywords rather than initial-statement-keywords.
>>
>> The remaining initial-declaration-keywords are "let" and "const". We already made "let" insane regarding these issues in sloppy mode, so I'm going to ignore that. But let's consider "const" and strict "let". These already cannot appear at the beginning of an expression, so it would not break anything to add them to the prohibition list for the beginning of expression statements.
>>
>> No current expression can add any binding to the scope in which the expression appears. Let's examine the consequences of having parens -- rather than containing a "{"-block to create a nested scope with a value (which would conflict with object literals), instead simply define a block-like nested scope with a value. This would allow declarations and statements within the parens, much like the current "do" proposal. It would even be consistent enough with the existing semantics of paren-surrounded function and class expressions: Someone who sees these as a function or class declaration within its own nested scope, whose value was the value being declared, would rarely be surprised by the subtle difference between that story and the current semantics.
>>
>> Having parens accept a list of declarations and statements rather than just an expressions seems like a radical change that must break something, but I can't find a problem. Am I missing something?
>>
>> Examples inline:
>>
>>
>>
>> On Mon, Jul 13, 2015 at 5:47 PM, Isiah Meadows <impinball at gmail.com> wrote:
>>>
>>> I was reading a recent thread where do-expressions simplified a common try-catch use case, and I was wondering if `do` could be simplified to an expression? It would allow for this to be solved very easily, but also add a lot more flexibility in this proposal, as well as avoiding some ugly nested braces.
>>>
>>> I know it would cause an ambiguity with `do-while` loops, but that could be resolved with a single token lookahead of "if the next token is the keyword `while`, then the block body is the body of a do-while loop, else it is the body of the block statement in a `do` expression".
>>>
>>> As for the EBNF, do-expressions could be parsed with a goal symbol of either `+While` or `-While`, with do-while statements spec-wise effectively being treated as do-expressions without an init part run repetitively, but mandated to be statements.
>>>
>>> ```js
>>> // Do expression
>>> let foo = do {
>>>   foo(0)
>>> };
>>
>>
>> let foo = (foo(0));
>>
>> This seems as broken as the original. In both cases, unless I'm missing something, this is a TDZ violation when the right side evaluates foo. Mistake?

Yep...s/foo/anything but foo/ ;)

>>
>>
>>
>>
>>>
>>>
>>> let tried = do try {
>>>   foo(0)
>>> } catch (e) {
>>>   throw e
>>> };
>>
>>
>> let tried = (try { foo(0) } catch (e) { throw e });
>>
>>
>>>
>>>
>>> // Do-while statement
>>> let i = 0;
>>> do {
>>>   foo(i)
>>> } while (i++ < 10);
>>>
>>> // Combined:
>>> let i = 0;
>>> let foo9 = do do {
>>>   foo(i) // can have side effects, foo9 = foo(9)
>>> } while (i++ < 10);
>>> ```
>>
>>
>> let i = 0;
>> let foo9 = (do { foo(i) } while (i++ < 10));
>>
>>
>>>
>>>
>>> Another example of where this could come in handy: simplifying asynchronous code.
>>>
>>> ```js
>>> function readConfig() {
>>>   fs.readFileAsync('config.json', 'utf8')
>>>     .then(JSON.parse)
>>>     .then(contents => do if (contents.unexpectedProperty) {
>>>       throw new Error('Bad property') // rejects the promise
>>>     } else {
>>>       doSomething(contents)
>>>     })
>>>     .catch(err => process.domain.emit('err', error))
>>> }
>>
>>
>> ...
>> .then(contents => (if (contents.unexpectedProperty) {
>> ...
>> }))
>> ...
>>
>>>
>>>
>>> // With only block statement
>>> function readConfig() {
>>>   fs.readFileAsync('config.json', 'utf8')
>>>     .then(JSON.parse)
>>>     .then(contents => do {
>>>       if (contents.unexpectedProperty) {
>>>         throw new Error('Bad property') // rejects the promise
>>>       } else {
>>>         doSomething(contents)
>>>       }
>>>     })
>>>     .catch(err => process.domain.emit('err', error))
>>> }
>>>
>>> // Without do-expressions
>>> function readConfig() {
>>>   fs.readFileAsync('config.json', 'utf8')
>>>     .then(JSON.parse)
>>>     .then(contents => {
>>>       if (contents.unexpectedProperty) {
>>>         throw new Error('Bad property') // rejects the promise
>>>       } else {
>>>         doSomething(contents)
>>>       }
>>>     })
>>>     .catch(err => process.domain.emit('err', error))
>>> }
>>> ```
>>>
>>> As you can see, the more general version does simplify things a little.
>>>
>>> Also, if-statements look better than long ternaries IMHO, and are less repetitive than their counterpart, repeated assignment (us lazy typists...):
>>>
>>> ```js
>>> let foo = do if (someCondition) {
>>>   value
>>> } else if (someOtherCondition) {
>>>   value + 1
>>> } else if (someEdgeCase) {
>>>   addressEdgeCase(value)
>>> } else {
>>>   value
>>> }
>>> ```
>>
>>
>> let foo = (if (someCondition) {
>> ...
>> })
>>
>>
>>>
>>>
>>> --
>>> Isiah Meadows
>>>
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>>
>>
>>
>>
>> --
>>     Cheers,
>>     --MarkM
>
>
>
>
> --
> Isiah Meadows




-- 
Isiah Meadows
d at domenic.me (2015-07-25T02:52:35.353Z)
On Mon, Jul 13, 2015 at 7:33 PM, Mark S. Miller <erights at google.com> wrote:

> This seems as broken as the original. In both cases, unless I'm missing something, this is a TDZ violation when the right side evaluates foo. Mistake?

Yep...s/foo/anything but foo/ ;)