Statements as expressions

I've a proposal that might help here (or not, probably not on the basis of my past suggestions):

Allow statement blocks to have modifiers.

I'm on my mobile (and have the kids to deal with), so I won`t make this as pretty as I'd like, but here the gist:

  • We'd like to make blocks that use reserved keywords like if/else/finally, switch exhibit different behaviour

  • Returning last expression is a common desired behaviour

  • We can`t change existing behaviour without potentially breaking things

  • We can`t add new reserved keywords for new behaviour

  • But we can do things to the keywords that would previously be syntactically illegal

  • I'm thinking of vue`s directive modifiers/arguments

  • We could make an if (+ its else/finally siblings) return expression values by doing something like if:expr () {} or if.expr () {}

That could certainly be a syntax option that we can choose. I think a "." would be a good choice, as it aligns with a number of other proposals in the pipeline, like function.sent, debugger.log, await.all, etc. But there's also the resource management proposal, which is currently taking the route of having two consicutive words work like a single operator ("try using"/"using value").

So, either option works for syntax - a two-word construct (like "with if"), or a construct with a dot (like "if.expr", "expr.if", "do.if", etc). There shouldn't be a problem with doing either choice, and I don't really have a strong preference one way or another.

I know it's a little early, as we don't even have a clear idea of how we want the syntax for all of this to look, but I decided to make this proposal repo anyways so that we can focus different discussion points in different issues, as needed. Feel free to contribute ideas there, or keep the conversation going here.

I did make a couple issues about points that were being discussed in this thread to get things started.

  • This issue brings up @lightmare's point that perhaps we don't want to add a new expression-if syntax construct, because we already have the ternary operator.
  • This issue talks about alternative syntax ideas we could do for try-catch, which includes @lightmare's catch-without-try idea, and the error-catching-pipeline-operator I brought up.
  • This issue talks about @JackWorks alternative idea for declaration syntax.
1 Like

I can see people wanting to do general imperative programming when using the pattern matching proposal. This also helps ensure that using match is always the better alternative to a switch to avoid teams discussing which one to use.

const result = match (v) {
  when (1) do {
     console.log('matched when');
     await otherSideEffect();
     'one';
  }
  else do {
    console.log('took else');
    'default';
  }
}

EDIT: I like the ideas on still having an expr { } block to allow this style.

1 Like

Ahh, you're right, that's a case I didn't think of. It would be useful to do imperative programming within a match expression. That'll be something important to think about.

1 Like

I noticed @JackWorks presented this idea, with the expr blocks on the do-expression proposal also (see here) - just thought I would throw the link into this thread, as it's relevant.

1 Like

Sorry if this has already been addressed, but how would your proposal handle loops?

Also, not a fan of do ... in - it seems like a precedence hazard waiting to happen.

The problem with loops is that, with only a handful of exceptions, they necessitate operating on mutable logic. Many languages get by without them, and I think while operating in an expression context it can be good to not have access to them. Instead, functions such as .map(), .filter(), and .reduce() can be used (though I'm not actually a fan of .reduce()). Though, if we think loops are valuable as expressions, I'm open to discussing it.

And yes, do ... in is indeed a hazard. I'm currently running with the following syntax instead:

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

This proposal is much more pragmatic than do-expressions.

I've just proposed a very similar syntax for IIFEs that uses do function, do async and do => (and possibly do class).

Slightly off topic, but isn't the following grammar dependent on significant whitespace?

const result = match (v) {
    ...
}

How would this parse?

const result = match(v)
{ 
    ...
}

Yes. It would be a function call to the variable β€œmatch”, and the next line would be separate - and depending on the syntax of the match block, it may or may not be a syntax error.

2 Likes