Re: Another statement expression-related proposal
Inline. On Wed, Nov 2, 2016, 01:01 Bob Myerswrote: > Just a random thought, but would `{= =}` work for expression blocks? > > ```js > // plain block > const foo = {= let a = 1; a =}; > > assert.equal(foo, 1) > > // if-else > let cond = false > const bar = {= if (cond) "hi" else "bye" =}; > > assert.equal(bar, "bye") > > // try-catch > let e = new Error() > const error = {= try { throw e } catch (e) { e } =}; > assert.equal(error, e) > ``` > In theory, yes, but it doesn't exactly look very pretty (too many equals signs and curly braces). > > I don't know about the loop idea. It seems like it's trying to do too much. > The loop thing is a bit extra, complicating things some, but I feel it's merited by the ability to avoid a lot of the confusion when using loops with the current `do` expression proposal (loops currently act like `reduce`, which is incredibly unintuitive). > On Wed, Nov 2, 2016 at 10:13 AM, Isiah Meadows > wrote: > > Yes, there's been a bit of talk about modifying the `do` proposal in > various ways (like allowing more than a block, using `=` to > differentiate, etc.), but each of these have potential ambiguities > (like conflicting with `do-while` or object literal syntax, > respectively), and give unintuitive results with loops. > > Here's my idea: prepend a `::` to any non-expression statement, and it > becomes an expression. The last statement's value (as if through > `eval`) is used as the return value, with exception of loops, which > return an array generated from their loop body. Here's a few examples > to clarify: > > ```js > // plain block > const foo = :: { let a = 1; a } > assert.equal(foo, 1) > > // if-else > let cond = false > const bar = :: if (cond) "hi" else "bye" > assert.equal(bar, "bye") > > // try-catch > let e = new Error() > const error = :: try { throw e } catch (e) { e } > assert.equal(error, e) > > // while loop > let i = 0 > const range = :: while (i < 10) i++ > assert.deepEqual(range, [ > 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, > ]) > > // for + nested if-else > const fizzBuzz = :: for (let i = 0; i < 100; i++) { > if (i % 15) "FizzBuzz" > else if (i % 3) "Fizz" > else if (i % 5) "Buzz" > // If no expression is evaluated in the body, then no value > // is pushed. > } > assert.deepEqual(fizzBuzz, [ > // 100 lines of the classic "Fizz", "Buzz", and "FizzBuzz" > ]) > ``` > > What do you all think of this? > > --- > > To clarify, here's some more detailed semantics: > > ### Grammar > > - `:: ExpressionStatement` > - `:: Declaration` > - `:: VariableStatement` > > These are early errors, and they are all redundant, anyways, since you > already have a value you could use. > > - `:: ContinueStatement` > - `:: BreakStatement` > - `:: ReturnStatement` > - `:: DebuggerStatement` > - `:: ThrowStatement` > - `:: EmptyStatement` > > These are also early errors, since there's no real value you can > associate with them. > > - `:: BlockStatement` > - `:: IfStatement` > - `:: SwitchStatement` > - `:: WithStatement` > - `:: TryStatement` > > 1. Let `completion` be ? ExecuteStatement(`statement`), where > `statement` is one of the statements above. > 2. If `completion` is *none*, return `undefined` > 3. Otherwise, return `completion`. > > - `:: IterationStatement` > > 1. Return ? ExecuteIterationStatement(`statement`), where `statement` > is one of the statements above. > > - `:: LabelledStatement` > > This works similarly, but has an outer label instead. The same above > statements are also similarly banned as `LabelledItem` entries. > Additionally, the Annex B extension for FunctionDeclaraions are also > early errors. > > (Should these even be allowed? I'm open to making this an early error > instead.) > > ### Abstract Operation ExecuteStatement(`statement`) > > 1. If `statement` is an IterationStatement: > 1. Let `list` be a new empty list. > 2. Evaluate `statement`, but for each `child` statement: > 1. Let `result` be ? ExecuteStatement(`child`). > 2. If `result` is not *empty*, then append `result` to `list`. > 3. Return `list`. > 2. If `statement` is an ExpressionStatement: > 1. Return the result of evaluating the expression within. > 3. If `statement` is a `BreakStatement` or `ContinueStatement`: > 1. Evaluate `statement` > 2. Return *empty*. > 4. If `statement` is a `Declaration`: > 1. Evaluate `statement`. > 2. Return the value of the resulting declaration > 5. Otherwise: > 1. Let `last` be *empty* > 2. Evaluate `statement`. For each `child` statement: > 1. Let `last` be ? ExecuteStatement(`child`). > 3. Note: `last` is the final expression's value, or `empty` if there > was no final expression. > 4. Return `last`. > > (I probably missed several edge cases, but this is just a mailing list > strawman.) > > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > >
Re: Another statement expression-related proposal
Just a random thought, but would `{= =}` work for expression blocks? ```js // plain block const foo = {= let a = 1; a =}; assert.equal(foo, 1) // if-else let cond = false const bar = {= if (cond) "hi" else "bye" =}; assert.equal(bar, "bye") // try-catch let e = new Error() const error = {= try { throw e } catch (e) { e } =}; assert.equal(error, e) ``` I don't know about the loop idea. It seems like it's trying to do too much. On Wed, Nov 2, 2016 at 10:13 AM, Isiah Meadowswrote: > Yes, there's been a bit of talk about modifying the `do` proposal in > various ways (like allowing more than a block, using `=` to > differentiate, etc.), but each of these have potential ambiguities > (like conflicting with `do-while` or object literal syntax, > respectively), and give unintuitive results with loops. > > Here's my idea: prepend a `::` to any non-expression statement, and it > becomes an expression. The last statement's value (as if through > `eval`) is used as the return value, with exception of loops, which > return an array generated from their loop body. Here's a few examples > to clarify: > > ```js > // plain block > const foo = :: { let a = 1; a } > assert.equal(foo, 1) > > // if-else > let cond = false > const bar = :: if (cond) "hi" else "bye" > assert.equal(bar, "bye") > > // try-catch > let e = new Error() > const error = :: try { throw e } catch (e) { e } > assert.equal(error, e) > > // while loop > let i = 0 > const range = :: while (i < 10) i++ > assert.deepEqual(range, [ > 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, > ]) > > // for + nested if-else > const fizzBuzz = :: for (let i = 0; i < 100; i++) { > if (i % 15) "FizzBuzz" > else if (i % 3) "Fizz" > else if (i % 5) "Buzz" > // If no expression is evaluated in the body, then no value > // is pushed. > } > assert.deepEqual(fizzBuzz, [ > // 100 lines of the classic "Fizz", "Buzz", and "FizzBuzz" > ]) > ``` > > What do you all think of this? > > --- > > To clarify, here's some more detailed semantics: > > ### Grammar > > - `:: ExpressionStatement` > - `:: Declaration` > - `:: VariableStatement` > > These are early errors, and they are all redundant, anyways, since you > already have a value you could use. > > - `:: ContinueStatement` > - `:: BreakStatement` > - `:: ReturnStatement` > - `:: DebuggerStatement` > - `:: ThrowStatement` > - `:: EmptyStatement` > > These are also early errors, since there's no real value you can > associate with them. > > - `:: BlockStatement` > - `:: IfStatement` > - `:: SwitchStatement` > - `:: WithStatement` > - `:: TryStatement` > > 1. Let `completion` be ? ExecuteStatement(`statement`), where > `statement` is one of the statements above. > 2. If `completion` is *none*, return `undefined` > 3. Otherwise, return `completion`. > > - `:: IterationStatement` > > 1. Return ? ExecuteIterationStatement(`statement`), where `statement` > is one of the statements above. > > - `:: LabelledStatement` > > This works similarly, but has an outer label instead. The same above > statements are also similarly banned as `LabelledItem` entries. > Additionally, the Annex B extension for FunctionDeclaraions are also > early errors. > > (Should these even be allowed? I'm open to making this an early error > instead.) > > ### Abstract Operation ExecuteStatement(`statement`) > > 1. If `statement` is an IterationStatement: > 1. Let `list` be a new empty list. > 2. Evaluate `statement`, but for each `child` statement: > 1. Let `result` be ? ExecuteStatement(`child`). > 2. If `result` is not *empty*, then append `result` to `list`. > 3. Return `list`. > 2. If `statement` is an ExpressionStatement: > 1. Return the result of evaluating the expression within. > 3. If `statement` is a `BreakStatement` or `ContinueStatement`: > 1. Evaluate `statement` > 2. Return *empty*. > 4. If `statement` is a `Declaration`: > 1. Evaluate `statement`. > 2. Return the value of the resulting declaration > 5. Otherwise: > 1. Let `last` be *empty* > 2. Evaluate `statement`. For each `child` statement: > 1. Let `last` be ? ExecuteStatement(`child`). > 3. Note: `last` is the final expression's value, or `empty` if there > was no final expression. > 4. Return `last`. > > (I probably missed several edge cases, but this is just a mailing list > strawman.) > ___ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Another statement expression-related proposal
Yes, there's been a bit of talk about modifying the `do` proposal in various ways (like allowing more than a block, using `=` to differentiate, etc.), but each of these have potential ambiguities (like conflicting with `do-while` or object literal syntax, respectively), and give unintuitive results with loops. Here's my idea: prepend a `::` to any non-expression statement, and it becomes an expression. The last statement's value (as if through `eval`) is used as the return value, with exception of loops, which return an array generated from their loop body. Here's a few examples to clarify: ```js // plain block const foo = :: { let a = 1; a } assert.equal(foo, 1) // if-else let cond = false const bar = :: if (cond) "hi" else "bye" assert.equal(bar, "bye") // try-catch let e = new Error() const error = :: try { throw e } catch (e) { e } assert.equal(error, e) // while loop let i = 0 const range = :: while (i < 10) i++ assert.deepEqual(range, [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ]) // for + nested if-else const fizzBuzz = :: for (let i = 0; i < 100; i++) { if (i % 15) "FizzBuzz" else if (i % 3) "Fizz" else if (i % 5) "Buzz" // If no expression is evaluated in the body, then no value // is pushed. } assert.deepEqual(fizzBuzz, [ // 100 lines of the classic "Fizz", "Buzz", and "FizzBuzz" ]) ``` What do you all think of this? --- To clarify, here's some more detailed semantics: ### Grammar - `:: ExpressionStatement` - `:: Declaration` - `:: VariableStatement` These are early errors, and they are all redundant, anyways, since you already have a value you could use. - `:: ContinueStatement` - `:: BreakStatement` - `:: ReturnStatement` - `:: DebuggerStatement` - `:: ThrowStatement` - `:: EmptyStatement` These are also early errors, since there's no real value you can associate with them. - `:: BlockStatement` - `:: IfStatement` - `:: SwitchStatement` - `:: WithStatement` - `:: TryStatement` 1. Let `completion` be ? ExecuteStatement(`statement`), where `statement` is one of the statements above. 2. If `completion` is *none*, return `undefined` 3. Otherwise, return `completion`. - `:: IterationStatement` 1. Return ? ExecuteIterationStatement(`statement`), where `statement` is one of the statements above. - `:: LabelledStatement` This works similarly, but has an outer label instead. The same above statements are also similarly banned as `LabelledItem` entries. Additionally, the Annex B extension for FunctionDeclaraions are also early errors. (Should these even be allowed? I'm open to making this an early error instead.) ### Abstract Operation ExecuteStatement(`statement`) 1. If `statement` is an IterationStatement: 1. Let `list` be a new empty list. 2. Evaluate `statement`, but for each `child` statement: 1. Let `result` be ? ExecuteStatement(`child`). 2. If `result` is not *empty*, then append `result` to `list`. 3. Return `list`. 2. If `statement` is an ExpressionStatement: 1. Return the result of evaluating the expression within. 3. If `statement` is a `BreakStatement` or `ContinueStatement`: 1. Evaluate `statement` 2. Return *empty*. 4. If `statement` is a `Declaration`: 1. Evaluate `statement`. 2. Return the value of the resulting declaration 5. Otherwise: 1. Let `last` be *empty* 2. Evaluate `statement`. For each `child` statement: 1. Let `last` be ? ExecuteStatement(`child`). 3. Note: `last` is the final expression's value, or `empty` if there was no final expression. 4. Return `last`. (I probably missed several edge cases, but this is just a mailing list strawman.) ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss