The only gripes I have with do expressions is the inability to specify the value produced in an obvious and uniform way, also are do expressions capable of being labelled?
- Matthew Robb On Tue, Jul 14, 2015 at 3:31 AM, Andreas Rossberg <[email protected]> wrote: > 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 > >
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

