Generalize do-expressions to statements in general?

Isiah Meadows impinball at gmail.com
Mon Jul 13 22:47:19 UTC 2015


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 tried = do 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);
```

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))
}

// 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
}
```

-- 
Isiah Meadows
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150713/201b7b12/attachment.html>


More information about the es-discuss mailing list