ponyfoo.com

Proposal: “Statements as Expressions” using do

Fix
A relevant ad will be displayed here soon. These ads help pay for my hosting.
Please consider disabling your ad blocker on Pony Foo. These ads help pay for my hosting.
You can support Pony Foo directly through Patreon or via PayPal.

A proposal for do statements has been classified as Stage 0 for a while, and it might be an interesting solution for some problems we can find in JavaScript.

When JavaScript expressions are evaluated, they produce a single value.

3 * 10
// <- 30

If we want to add a condition in an expression, we need to use ternary expressions or logical operators. The following example displays both alternatives, although the former is usually preferred.

[1, -1, -0.5].map(x => x > 0 ? x * 10 : -x * 10)
// <- [10, 10, 5]
[1, -1, -0.5].map(x => x > 0 && x * 10 || -x * 10)
// <- [10, 10, 5]

It can be confusing to create side effects, but you can achieve that through use of commas.

sideEffect(), 3 * 10
// <- 30

It’s not possible to declare variables you might need for temporary storage within an expression. As such, you typically extract these variables into the enclosing scope. More often than not, that’s better for readability anyways, so it doesn’t have a hugely negative impact.

Using do

The do expression proposal lets you write a block of statements to be evaluated. The “completion value” is returned as the result of a do expression. In the following example, there’s just a 3 * 10 expression in our block, so that’s our completion value, and 30 is returned.

do { 3 * 10 } // just an expression
// <- 30

The following bit of code is equivalent to the two .map examples we saw earlier. In this case, we use a do expression, allowing us to use if and else instead of ternary or logical operators.

[1, -1, -0.5].map(x => do { if (x > 0) { x * 10 } else { -x * 10 } })
// <- [10, 10, 5]

Side effects in do expressions become easier to read, and we are able to declare variables. In the following example we’re purposely missing a return statement, as do expressions already implicitly return, as we saw in the case of the if / else example. Naturally, const and let variables declared inside a do block are scoped to that block, while var variables are scoped to the containing function.

var data = do {
  const data = pullSomeData()
  doSomethingElse() // sideEffect
  data
}

Using do Today

It’s easy, there’s a Babel plugin we can use.

npm install --save-dev babel-plugin-syntax-do-expressions

Then add the following to your .babelrc file or the babel property in package.json.

{
  "plugins": ["syntax-do-expressions"]
}

That’s it.

Whenever you run the Babel CLI, it’ll understand do expressions.

Conditionals in JSX

A while back I wrote about “the weird parts” of using JSX – the JavaScript syntax extension Facebook built to help you write templates for React apps. Back then, I mentioned how sometimes you have to write code like the following when you want to conditionally render a piece of markup.

return (
  <nav>
    <Home />
    { loggedIn && <LogoutButton /> || <LoginButton /> }
  </nav>
);

With do expressions, you could get rid of the weird-looking and oft-confusing logical operators. This makes the code easier to read and saves you from having to deal with falsy expressions like 0 or ''.

return (
  <nav>
    <Home />
    {
      do {
        if (loggedIn) {
          <LogoutButton />
        } else {
          <LoginButton />
        }
      }
    }
  </nav>
)

When there’s larger pieces of markup it becomes more elegant to be able to use statements instead of expressions – and do let’s you do that. The do syntax makes it easier to read conditionals, allows you to use variables, and makes it clear when part of an expression is a side effect.

Liked the article? Subscribe below to get an email when new articles come out! Also, follow @ponyfoo on Twitter and @ponyfoo on Facebook.
One-click unsubscribe, anytime. Learn more.

Comments