# Statements as expressions

**URL:** <https://es.discourse.group/t/statements-as-expressions/894>\
**Category:** 💡 Ideas\
**Created:** [July 28, 2021, 3:46am UTC](https://es.discourse.group/t/statements-as-expressions/894 "2021-07-28T03:46:17Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [July 28, 2021, 3:46am UTC](https://es.discourse.group/t/statements-as-expressions/894/1 "2021-07-28T03:46:17Z")

</div>

This is intended to be a counter-proposal to [do expressions](https://github.com/tc39/proposal-do-expressions).

Do expressions are really nice, and I would love it if we had them in the language, but they're also a bit ... odd. The original idea seems nice - turn any statement into an expression by putting it in a do block, until you realize that there's a bunch of things that should really not be turned into expressions, such as if without else, a for loop, etc, so they're currently adding [a lot of exceptions](https://github.com/tc39/proposal-do-expressions/tree/3ef6d463b8163cbf222846b40d17178cca36e9e1#limitations) to what's allowed at the end of a do block.

Turns out, if you actually look at [the list of valid javascript statements](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements), there's really only a small handful of statements that are actually useful as expressions. What if, we just create an expression form of useful statements (such as if and try/catch), instead of bringing the do block proposal into the language, with all of the oddities it brings with it.

[There](https://github.com/tc39/proposal-do-expressions/issues/39) [is](https://github.com/tc39/proposal-do-expressions/issues/9) [actually](https://github.com/tc39/proposal-do-expressions/issues/7) [tons](https://github.com/tc39/proposal-do-expressions/issues/53#issuecomment-887600244) [and](https://github.com/tc39/proposal-do-expressions/issues/1) [tons](https://github.com/tc39/proposal-do-expressions/issues/36) [and](https://github.com/tc39/proposal-do-expressions/issues/33#issuecomment-425186605) [tons](https://github.com/tc39/proposal-do-expressions/issues/11) [of discussion](https://github.com/tc39/proposal-do-expressions/issues/43) on the do block proposal of people trying to change the syntax of do blocks, so that you can just use a statement in an expression position without creating an extra nested block. What I'm proposing here is based in part of some of the feedback I've left in those discussions. These ideas in general seems different enough that I thought it might be worth making a separate proposal out of it, instead of changing do blocks into something it's not.

## The proposal

The javascript features I think would be most valuable as an expression would be: if, try/catch, and declarations, so I propose that we simply add an expression form for these three features.

**do if**

The syntax for do if is:

```javascript
do if (<condition>) <expression> [else if (<condition>) <expression>] else <expression>

```

You're not allowed to have a `do if` without an else.

Example:

```javascript
const result = (
  do if (numb === 0) 'zero'
  else if (numb === 1) 'one'
  else if (numb === 2) 'two'
  else 'two+'
)

```

**do try**

The syntax for `do try` is this:

```javascript
do try <expression> catch (<identifier>) <expression>

```

Example:

```javascript
const rethrow = err => { throw err }
const result = (
  do try dangerFunction()
  catch (err) err instanceof NotFound ? null : rethrow(err)
)

```

**do const**

This is inspired by functional languages such as haskell. Whatever declarations that go in `do const` will only exist within the `do const` expression. Whatever goes after the `in` will become the completion value of this expression.

The syntax is:

```javascript
do const <identifier> = <expression>[, <identifier> = <expression>] in <expression>

```

Example:

```javascript
const result = (
  do const
    x = getX(),
    y = getY(),
    z = x + y
  in processZ(z)
)

```

## But what about...?

throw? Expression-throw is already being treated in its own proposal [here](https://github.com/tc39/proposal-throw-expressions). If that doesn't go through, we can always add on a `do throw <expression>` syntax.

switch? The need for switch should be replaced by the [pattern match proposal](https://github.com/tc39/proposal-pattern-matching), which provides an expression construct.

break? continue? return? These are all things that the do block supports, but I'm not convinced that's a good thing. If others disagree, we can discuss it, and potentially add "`do break/continue/return`" - some of them could potentially be added without a do prefix too.

for loops? How would you want this to behave? Potentially the most intuitive answer would be to have a for loop generate an array of values generated from each iteration, e.g. `(do for (x of [1, 2, 3]) x + 1) === [2, 3, 4]`, but, we already have array.map() to provide this functionality. I currently don't see a convincing use case for a for loop as an expression.

while loops? While loops are a very imperative control structure that just don't fit well as an expression. I'm not sure how you would even begin to model this as an expression, but if you have any ideas, and you think a "`do while`" would be valuable, we can discuss it.

Imperative programming in an expression context? This is probably the main thing that do blocks provide that won't be provided by this proposal. In a do block, you can do any kind of imperative programming, right in the middle of an expression. You can loop over an array, updating mutable state as you go along, then finally provide a completion value as the result of this imperative logic. I don't think this is a necessary feature though. Many functional languages out there don't provide any way to do imperitive programming, and yet they seem to get along just fine without it. You don't _need_ a while loop to survive. I do think there are use cases for impleritive programming, but does it have to be _right_ in the middle of an expression? If it really does, you can always use an IIFE.

## What if we just toss the do prefix, and turn if/try/etc into expressions

There are some parsing concerns about this kind of idea, which was discussed [here](https://github.com/tc39/proposal-do-expressions/issues/39). Additionally, `if` and `do if` behave differently and have different grammar rules (`do if` requires an else block while `if` does not, and it can only contain expressions, not statements). Same is true with `try` vs `do try` and `const` vs `do const`. I think it makes sense to just leave them as separate control structures entirely, instead of morphing them into the same thing.

## General example

Here's an example that combines many of these expressions together to form a more complicated function. Not everyone will choose to nest them to this extend, but you certainly can. In fact, if you wanted to, using these constructs you could make all of your function bodies be constructed entirely out of expressions like you would in a functional language.

```javascript
// This snippet is relying on the throw-as-expression proposal going through.
const getUserInfo = userId => (
  do const
  userData = (
    do try (
      await fetchUserData(userId)
    ) catch (err) (
      err instanceof NotFoundError ? null : throw err
    )
  ),
  dbData = await fetchFromDb(userId),
  in {
    name: userData.name,
    birthday: userData.birthday,
    dbId: dbData.id,
  }
)

```

## Feedback

What do you think? Does it feel intuitive? Is there anything else you can think of, that you wish you could do in an expression context? I dismissed many possibilities, such as return, break, while loops, etc - do you agree that these shouldn't be in an expression, or would you find these features as valuable in an expression context?

And most importantly, can you think of any code snippet that can be written cleanly with the do expression proposal, that can't be written as nicely with this current proposal? If so, it means we're not covering all of the useful features that do blocks provide. I personally can't think of anything.

---

<div class="post-metadata">

**Author:** ![lightmare](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/lightmare/32/843_2.png) [@lightmare](https://es.discourse.group/u/lightmare)\
**Post date:** [July 28, 2021, 7:42am UTC](https://es.discourse.group/t/statements-as-expressions/894/2 "2021-07-28T07:42:08Z")

</div>

You don't need the `do` keyword in that case. Just allow `if` or `try` as expressions.

> [@theScottyJam](#):
>
> Example:
> 
> ```javascript
> const result = (
> do const
> x = getX(),
> y = getY(),
> z = x + y
> in processZ(z)
> )
> 
> ```

Would parse as `z = (x + y in processZ(z))`.  
You'd need to use a keyword that's not an infix operator, like:

```javascript
  with const
    x = getX(),
    y = getY(),
    z = x + y
  do processZ(z)

```

---

<div class="post-metadata">

**Author:** ![lightmare](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/lightmare/32/843_2.png) [@lightmare](https://es.discourse.group/u/lightmare)\
**Post date:** [July 28, 2021, 10:51am UTC](https://es.discourse.group/t/statements-as-expressions/894/3 "2021-07-28T10:51:32Z")

</div>

I wanted to better explain why I think you don't need `do` before `if/try`. Then I realized nobody needs `do if` — JS already has conditional expressions. So I'll only discuss `do try` (but note that `do if` has an even worse case of the same issue, on top of being redundant).

```javascript
do try expr catch (e) expr NEXT

```

If `expr` can be an object literal, then you might not be able to tell whether that's a `do-try-expression` or a `do..while` loop, until you get to the NEXT token. And you need to make sure it's unambiguous.

```javascript
// currently valid JS
do try { foo: bar() } catch (e) { oops }
while (cond)
{ foo: bar() }

```

```javascript
// parsed as
do { try ... catch ... } while (cond); // do..while loop
{ foo: bar() }; // object literal

```

You need to specify that the above must not be parsed as:

```javascript
do try // do try expression 
  { foo: bar() } // object literal
catch (e)
  { oops } // object literal
;
while (cond) { // while loop
  foo: // label
  bar();
}

```

You can either:

- forbid object literals;  
in this case, the `do` prefix does not do anything useful, because it's the token after `try` that decides whether it's a statement (left curly brace) or expression (anything else);  
or
- adopt the rule by which `do-expression` proposal avoids ambiguity — wherever `do` can start a `do..while` loop, it does. If you want to force parsing a `do-expression` in a place where it would otherwise parse as `do..while` statement, wrap it in parentheses;  
in this case, you could drop the `do` and make that rule for `try` alone;  
edit: or
- drop the whole `do try` prefix:

```javascript
res = expr catch (e) handler;

```

or

```javascript
res = expr catch e => handler;
// here => is not an arrow function, just a delimiter;
// think of it like a ternary operator:
// expr1 `catch` identifier `=>` expr2

```

---

<div class="post-metadata">

**Author:** ![kornel](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/kornel/32/926_2.png) [@kornel](https://es.discourse.group/u/kornel)\
**Post date:** [July 28, 2021, 11:41am UTC](https://es.discourse.group/t/statements-as-expressions/894/4 "2021-07-28T11:41:38Z")

</div>

`do const` is the weirdest of them all. Given that there is `for(const x in y)`, it does things in surprising ways. I would expect the `const bindings` to somehow destructure the `in` expression, and I wouldn't expect the `in` to be the value of the whole expression.

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [July 28, 2021, 1:39pm UTC](https://es.discourse.group/t/statements-as-expressions/894/5 "2021-07-28T13:39:37Z")

</div>

@lightmare

Thanks everyone for the feedback.

Yeah, it looks like there's a number of parsing errors with what I just proposed.

> [@lightmare](#):
>
> I wanted to better explain why I think you don't need `do` before `if/try`. Then I realized nobody needs `do if` — JS already has conditional expressions.

Conditionals don't support else-if, which is the big motivation for them. Sure you can nest them, but a lot of people forbid doing so, as that can feel pretty confusing and tricky. `do if` provides a natural way of doing so.

> [@lightmare](#):
>
> Would parse as `z = (x + y in processZ(z))`.  
> You'd need to use a keyword that's not an infix operator, like:

This one I actually realized soon after posting this. Yes, we'll need something else. The `with const ... do ...` is a pretty intuitive way of doing it, I like that :).

> [@lightmare](#):
>
> If `expr` can be an object literal, then you might not be able to tell whether that's a `do-try-expression` or a `do..while` loop, until you get to the NEXT token. And you need to make sure it's unambiguous.

Good point. Another option is to change the prefix. i.e. `do.if`/`do.try`. or `with if`/`with try` to be consistent with your `with const` idea. It would also be possible to drop the `try` prefix as you suggested and turn `catch` into a binary operator, though, it is nice having `try` there, making the boundaries of what's being caught very explicit (as opposed to relying on operator precedence), and the try looks nice when you're breaking it up over multiple lines, but I also see value in just having catch as a binary operator.

@kornel

> [@kornel](#):
>
> `do const` is the weirdest of them all. Given that there is `for(const x in y)`, it does things in surprising ways. I would expect the `const bindings` to somehow destructure the `in` expression, and I wouldn't expect the `in` to be the value of the whole expression.

You're right, it is a little confusing. Do you find @lightmare's suggested syntax of `with const ... do ...` more intuitive? I just automatically reached for the `in` keyword, as that's how many other languages do declarations as expressions, but I should have realized that `in` already has meaning and shouldn't be reused in this context.

---

<div class="post-metadata">

**Author:** ![lightmare](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/lightmare/32/843_2.png) [@lightmare](https://es.discourse.group/u/lightmare)\
**Post date:** [July 28, 2021, 2:00pm UTC](https://es.discourse.group/t/statements-as-expressions/894/6 "2021-07-28T14:00:41Z")

</div>

> [@theScottyJam](#):
>
> Conditionals don't support else-if, which is the big motivation for them. Sure you can nest them, but a lot of people forbid doing so, as that can feel pretty confusing and tricky. `do if` provides a natural way of doing so.

There is no difference in expressiveness, it's purely syntactic. You just replace "`x ?`" with "`if (x)`" and "`:`" with "`else`".

```javascript
const result = (
  do if (numb === 0) 'zero'
  else if (numb === 1) 'one'
  else if (numb === 2) 'two'
  else 'two+'
)

```

is the same as:

```javascript
const result = (
  (numb === 0) ? 'zero'
  : (numb === 1) ? 'one'
  : (numb === 2) ? 'two'
  : 'two+'
)

```

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [July 28, 2021, 2:43pm UTC](https://es.discourse.group/t/statements-as-expressions/894/7 "2021-07-28T14:43:13Z")

</div>

I agree - it's purely syntactice. But `do if`/`with if` reads better, especially when you start nesting these things:

```javascript
const f = (x, y) =>
  with if (y === 0) (
    with if (x === 0) throw new Error('Both x and y can not be zero!')
    else if (x < 0) throw new Error('x can not be negative')
    else x
  ) else if (x === 0) (
    y
  ) else (
    Math.min(x, y)
  )

const f = (x, y) =>
  y === 0 ? (
    x === 0 ? throw new Error('Both x and y can not be zero!')
    : x < 0 ? throw new Error('x can not be negative')
    : x
  )
  : x === 0 ? y
  : Math.min(x, y)

```

I see people use ternaries in the format you showed, but I've never seen them nest nested ternary like in the above example, and I'm not sure that kind of pattern will really catch on. A lot of people already dislike the idea of nested ternaries (and many style guides forbid them), even though a normal `if - else if - else` is just a nested `if else` in the same manner. There does seem to be a desire out there for an expression form if "if" - just reading through different motivating examples people give in the do expression proposal, many of those examples seem to be featuring how nice it is to do an if/else if/else as an expression.

But, you're also right. Even if we simply add an expression-try-catch and expression declarations, we should end up with just as much power as the do expression proposal has. The expression-if would be more of an optional nice-to-have, not a have-to-have-in-order-to-make-javascript-expression-oriented.

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [July 28, 2021, 3:04pm UTC](https://es.discourse.group/t/statements-as-expressions/894/8 "2021-07-28T15:04:32Z")

</div>

On second thought, the simpler we make this proposal, the better. We can just ditch expression-if for now - it can be discussed more at a later point if we want it. But, for now, we can focus on the minimum number of things we need to convert to expressions in order to replace the do expression proposal, and that's just declarations and try-catch - declarations likely being the most important thing.

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [July 28, 2021, 4:25pm UTC](https://es.discourse.group/t/statements-as-expressions/894/9 "2021-07-28T16:25:02Z")

</div>

I think the separation between statements and expressions is very important, and I strongly think that the `do { }` is a necessary signal that statements will appear in expression context. I would not be in favor of converting anything to an expression that's not already one (throw expressions, at stage 3, being the notable exception).

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [July 29, 2021, 6:22am UTC](https://es.discourse.group/t/statements-as-expressions/894/10 "2021-07-29T06:22:50Z")

</div>

> [@ljharb](#):
>
> (throw expressions, at stage 3, being the notable exception).

That one's unfortunately still at stage 2 🙁 - unless [the README](https://github.com/tc39/proposal-throw-expressions) is outdated.

> [@ljharb](#):
>
> I would not be in favor of converting anything to an expression that's not already one

Could you clarify this a bit? I assume from this statement that you would be opposed to something like this:

```javascript
const x = try f() catch (err) err.value

```

as we're giving "try" two different meanings depending on whether or not it's a statement or expression.

Are you comfortable with it, if we're prefixing the "try" with some other keyword in order to distinguish it as a completely different operator?

```javascript
const x = with try f() catch (err) err.value

```

Or would you prefer we try to entirely change the semantics of whatever expression-try-except we come up with, so it feels very different from the statement version? Maybe we even find different keywords instead of "try" and "catch" to use, to help make the distinction clearer?

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [July 29, 2021, 6:39am UTC](https://es.discourse.group/t/statements-as-expressions/894/11 "2021-07-29T06:39:24Z")

</div>

Ah, you’re right, it’s still stage 2.

Yes, i would be. I’m comfortable with do expressions, no more and no less.

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [July 29, 2021, 1:55pm UTC](https://es.discourse.group/t/statements-as-expressions/894/12 "2021-07-29T13:55:44Z")

</div>

> [@ljharb](#):
>
> I’m comfortable with do expressions, no more and no less.

Well, that's a shame 😥

I do know many other people are hoping the do expression proposal goes a different direction (as I've linked in to in my O.P.), so I'll try to keep pursuing this idea and see where it leads.

* * *

On another note, I was remembering [this "catch pipeline operator" proposal](https://es.discourse.group/t/error-dejection-operator/788) recently. It's intended to be a follow-on proposal to the pipeline operator that provides catch-handling semantics. i.e. if the pipeline operator is a sync version of promise.then(), then this proposed operator is a sync version of promise.catch().

Example:

```javascript
const result = getId()
  |> getUser(#)
  |^ # instanceof NotFoundError ? null : throw #
  |> getGroups(#)

```

In the above example, the "`|^`" operator will catch any errors on the left-hand side and pass that error to the right-hand side. It'll follow whatever syntax the pipeline operator follows (F# - where the right-hand side expects a function, or hack-style, where the right-hand side is an expression with sigils (#) that are replaced with the LHS's value).

I really love this proposal, and hope it goes in. If it does, then the only remaining thing that we would need is the ability to create declarations in an expression position.

---

<div class="post-metadata">

**Author:** ![senocular](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/senocular/32/642_2.png) [@senocular](https://es.discourse.group/u/senocular)\
**Post date:** [July 29, 2021, 1:59pm UTC](https://es.discourse.group/t/statements-as-expressions/894/13 "2021-07-29T13:59:14Z")

</div>

> [@theScottyJam](#):
>
> Well, that's a shame 😥

Sounds like it's time to go back to [coffeescript](https://coffeescript.org/#expressions).

---

<div class="post-metadata">

**Author:** ![jithujoshyjy](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jithujoshyjy/32/399_2.png) [@jithujoshyjy](https://es.discourse.group/u/jithujoshyjy)\
**Post date:** [July 29, 2021, 2:16pm UTC](https://es.discourse.group/t/statements-as-expressions/894/14 "2021-07-29T14:16:32Z")

</div>

sure do!  
The do expressions will benefit from the catch pipeline operator / error dejection operator.  
I recently had a thought about it, how will it handle Syntax Errors? I mean if the syntax is incorrect the operator itself isn't going to get parsed, let alone executed.  
It's not the right place to discuss this so I'll post the rest in the corresponding discussion.

---

<div class="post-metadata">

**Author:** ![MaxGraey](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/maxgraey/32/651_2.png) [@MaxGraey](https://es.discourse.group/u/MaxGraey)\
**Post date:** [August 3, 2021, 3:17pm UTC](https://es.discourse.group/t/statements-as-expressions/894/15 "2021-08-03T15:17:07Z")

</div>

Brw regarding "do proposal" I'm wondering why use "do" keyword instead arrow "=\>" which already partially has expression-based semantics combining with some control flow statement?  
do proposal:

```javascript
const abs = do {
  if (x < 0) x else y 
}

```

new (arrow based):

```javascript
const abs = if (x < 0) => x else y 
const abs = if x < 0 => x else y // parentheses are optional

```

do proposal:

```javascript
(do {
  while (cond) {
    // do something
  }
});

```

new (arrow based):

```javascript
while (cond) => {
   // do something
}

```

and etc

---

<div class="post-metadata">

**Author:** ![ljharb](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/ljharb/32/8_2.png) [@ljharb](https://es.discourse.group/u/ljharb)\
**Post date:** [August 3, 2021, 3:58pm UTC](https://es.discourse.group/t/statements-as-expressions/894/16 "2021-08-03T15:58:48Z")

</div>

An arrow would imply it's a function body, which has an impact on scoping, and await/yield/return, etc.

---

<div class="post-metadata">

**Author:** ![JackWorks](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jackworks/32/260_2.png) [@JackWorks](https://es.discourse.group/u/JackWorks)\
**Post date:** [August 4, 2021, 4:48am UTC](https://es.discourse.group/t/statements-as-expressions/894/17 "2021-08-04T04:48:36Z")

</div>

As implementor (in Typescript), I think this is the good way to do. Pick useful things into expression (this thread) to make expression powerful, instead of providing a statement wrapper (do expression block).

break, continue, return in the do expression open the gate of changing control flow (excepts throw) in the expression position. I don't know if it's a good idea.

And the forbidden-for or if-without-else problem, those problems does not exists in this thread.

The only problem I can see in this thread is how to handle temp variables. The syntax's looks not very suitable.

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [August 4, 2021, 7:07am UTC](https://es.discourse.group/t/statements-as-expressions/894/18 "2021-08-04T07:07:05Z")

</div>

Could you expound on your worries with handling temp variables? Are you mostly saying that the "do const" syntax idea is a bit clumsy to use? (I would agree with that)

---

<div class="post-metadata">

**Author:** ![JackWorks](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/jackworks/32/260_2.png) [@JackWorks](https://es.discourse.group/u/JackWorks)\
**Post date:** [August 4, 2021, 8:43am UTC](https://es.discourse.group/t/statements-as-expressions/894/19 "2021-08-04T08:43:45Z")

</div>

Yes. That syntax is a little strange.

Maybe we can combine these to get a better form of do expression:

1. The first step is the same as the main thread (make `if` and `try` to become expressions)
2. Add a new syntax `expr ExprBlock`. ExprBlock is a new kind of Block that can only contains `Expression` and `Declaration`, and `Declaration` cannot be in the last item of the block.
3. `ExprBlock`: `{}` (base case, evaluated as `undefined`)
4. `ExprBlock`: `{ Expression }` (same as `Expression`)
5. `ExprBlock`: `{ DeclarationOrExpression; Expression }` (note: `const` and `let` are not statements!)

So it will resolve this problem in a nice way:

```javascript
const val = expr {
    function r() { return Math.random() }
    const rnd = r()
    // Declaration in non-end is OK
    rnd * rnd
    // Expression is OK
}

const val2 = expr {
    var a = 1; // No! var is statement
    for (const a of b) a // No! for...of is statement
}

```

Furthermore, we can use this `ExprBlock` in `if`, `try` expression.

```javascript
const a = if (expr) {
    // This is a ExprBlock
    for (const a of b) a // No
    b.map(x => x) // Ok
} else {
}

```

How do you think?

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [August 4, 2021, 10:24pm UTC](https://es.discourse.group/t/statements-as-expressions/894/20 "2021-08-04T22:24:07Z")

</div>

@JackWorks - you've got some good ideas there. My main concern is that within an `expr block` everything looks like normal code, but it's actually a highly restricted block, and it may be unintuitive with which things can go in it and which can not. e.g. var can't be inside, but a function() {} declaration can - those make sense when I think about it, but that wouldn't have been my initial impression. One way to solve that is to limit it further, and make it so only const declarations can be used. Functions can be declared with const, and there really shouldn't be a need for a mutable binding here, so we can just disallow them.

* * *

I'm going to go back to my initial idea for a bit, with this example:

```javascript
const result = (
  do const
    x = getX(),
    y = getY(),
    z = x + y
  in processZ(z)
)

```

I think the most awkward part about this is the fact that it uses two layers of indentation, and the resulting `in processZ(z)` part is very separate from the preceding declarations. It just feels cumbersome to use. I think I've found a way to solve many of these awkward points with some minor adjustments.

```javascript
const result = (
  with x = getX() do
  with y = getY() do
  with z = x + y do
  processZ(z)
)

```

The syntax for this expression form of declaration is:

```javascript
with <identifier> = <expression> do <expression>

```

This syntax only lets you bind one identifier to a value. To bind multiple, you have to chain them together, like I've done in the above example. Now we only need one level of indentation, and the resulting `processZ(z)` expression is right next to the declarations.

Here's another syntax idea that also solve the same problems:

```javascript
const result = (
  with x = getX()
  with y = getY()
  with z = x + y
  do processZ(z)
)

```

```javascript
with <identifier> = <expression> [with <identifier> = <expression>...] do <expression>

```

This particular format has a pretty similar shape to your expression block idea, but its rules feel a little simpler to me.

```javascript
const result = expr {
  const x = getX()
  const y = getY()
  const z = x + y
  processZ(z)
}

```

Thoughts? Does that still feel cumbersome to use? I like that a lot better than my original idea (technically the original idea supported chaining and indenting like this too - I just didn't realize it)

[Next page](https://es.discourse.group/t/statements-as-expressions/894.md?page=2)
