Another statement expression-related proposal
# Bob Myers (8 years ago)
Just a random thought, but would {= =}
work for expression blocks?
// 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.
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 Meadows <isiahmeadows at gmail.com> 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 at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20161102/f9343433/attachment.html>
# Isiah Meadows (8 years ago)
Inline.
On Wed, Nov 2, 2016, 01:01 Bob Myers <rtm at gol.com> wrote:
Just a random thought, but would
{= =}
work for expression blocks?
// 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).
Inline. On Wed, Nov 2, 2016, 01:01 Bob Myers <rtm at gol.com> wrote: > 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 <isiahmeadows at gmail.com> > 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 at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20161102/e58e8f6a/attachment.html>
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 withdo-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 througheval
) 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:// 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
completion
be ? ExecuteStatement(statement
), wherestatement
is one of the statements above.completion
is none, returnundefined
completion
.:: IterationStatement
statement
), wherestatement
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
)statement
is an IterationStatement:list
be a new empty list.statement
, but for eachchild
statement:result
be ? ExecuteStatement(child
).result
is not empty, then appendresult
tolist
.list
.statement
is an ExpressionStatement:statement
is aBreakStatement
orContinueStatement
:statement
statement
is aDeclaration
:statement
.last
be emptystatement
. For eachchild
statement:last
be ? ExecuteStatement(child
).last
is the final expression's value, orempty
if there was no final expression.last
.(I probably missed several edge cases, but this is just a mailing list strawman.)