I don't see why you need parens at all, see my previous post. But I wouldn't make the do-less forms the base syntax,; rather, only short-hands for the general thing. In particular, because the ability to have an actual block inside an expression is one primary motivation for having do-expressions in the first place.
...Ah, it's 2015, and we still have to come up with ways to overcome the archaic statement/expression distinction from the stone ages. :) /Andreas On 14 July 2015 at 01:33, Mark S. Miller <[email protected]> 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 <[email protected]> > wrote: > >> I was reading a recent thread >> <https://esdiscuss.org/topic/allow-try-catch-blocks-to-return-a-value> 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? > > >> >> 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 >> [email protected] >> https://mail.mozilla.org/listinfo/es-discuss >> >> > > > -- > Cheers, > --MarkM > > _______________________________________________ > es-discuss mailing list > [email protected] > https://mail.mozilla.org/listinfo/es-discuss > >
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

