Scala 3 quiet syntax

I was reading the documentation at control-syntax-new.html.

Assuming that this is the latest, I note:

The condition of an if-expression can be written without enclosing parentheses if it is followed by a then or some indented code on a following line.

But, The condition of a while-loop can be written without enclosing parentheses if it is followed by a do.

This is not a big issue, but I was wondering why do cannot also be omitted (like then) if it is followed by some indented code. Would it make the language more regular if then and do were treated in the same way?

Thanks,
Rob

In fact, I think we’ll got back on always requiring a then after the if instead. Writing then is initially easily forgotten, but in the end the better uniformity wins. So, the following is valid:

Old style:

if (condition) 
  thenPart
else
  elsePart

New style

if condition then
  thenPart
else
  elsePart

But the following would be phased out:

if condition
  thenPart
else
  elsePart
4 Likes

That sounds good, thanks.

If there is time to tweak the links on the Dotty documentation pages to point to the current proposal that would be great, but I appreciate that you are very busy :wink:

Here’s a vote for high style over uniformity.

What about colons?

if condition:
  thenPart
else:
  elsePart

Also, would it be possible to combine the no-enclosing-parenthesis syntax with curly braces?

if condition then {
  thenPart
} else {
  elsePart
}

Colons are for type ascription. As such it’s not a great idea to use them to introduce blocks.

7 Likes

If we are so desperate to get rid of curly braces that we even consider replacing them by keywords, how do you feel about introducing keywords begin and end?

I’m not suggesting doing that. I’m just curious how people would feel about that.

I don’t understand why we would give up the simple, clear and consistent and very common syntax based on curly braces and replace it with a wild mix of curly braces, indentation and special keywords.

8 Likes

See -Yindent-colons. https://dotty.epfl.ch/docs/reference/other-new-features/indentation.html

Not only does doti fork the language, they re-introduce forking -Y!

1 Like

I thought that wouldn’t be a problem, as this is usually not a part of an expression but a part of a definition, but then there are anonymous functions:

if myList.exists(a: MyType => ...):
  thenPart

Yeah, this looks a bit confusing.

1 Like

I think this specific syntax is more about removing the enclosing parenthesis rather then omitting curly braces; this is why I asked if it would be possible to mix curly braces with the then syntax.

I would much rather see

xs.map { x =>
  val y = x - 1
  y * y
}

than

xs.map:
  x =>
      val y = x - 1
      y * y

Besides, this entire feature (optional braces) is still quite controversial.

2 Likes

Slightly besides the point, but I’ve proposed @ for this use case before. I think it looks nice, and it is backward-compatible (won’t break any code):

xs.map @ x =>
  val y = x - 1
  y * y

The rule would be: Anything that comes after @ (including indented blocks) is considered wrapped into a set of curly braces. Also, @ has least precedence and associates to the left.

So

xs.foldLeft @ init @ (a, x) =>
  val res = a + x
  res

means

xs.foldLeft { init } { (a, x) =>
  val res = a + x
  res
}

As for if/then/else, I think it’s perfect as it is.

3 Likes

Looks like the @ sometimes closes a previous place and sometimes it does not. What if I want to open a second curly brace without closing one?

2 Likes

That’s because it is left-associative. As with any operators, you can’t have it sometimes associate right and sometimes associate left.

Perhaps it would be more useful as a right-associative operator (like Haskell’s $), but I am not sure.

It’s almost like you’d want two paired operators. We could bikeshed that a bit, and I’m willing to kick it off by suggesting {} - there’s plenty of prior art, and it wouldn’t break any code :wink:

1 Like

No, I do not. The entire point is to avoid them.

The problem of paired operators is that they accumulate in annoying ways, making it harder to see which closing brace closes which opening one.
For example, compare f(a)(g(b)(h(c)(d))) with f(a) @ g(b) @ h(c)(d) (assuming right-associativity).
This is not to mention the fact that we’d like to avoid having to terminate functions passed as arguments with an extraneous } line, leveraging indentation syntax instead,

There’s also plenty of prior art with $ in Haskell.

1 Like

Maybe we can have an IDE plugin that makes curly braces look like something else.

1 Like

The issue I have with these sorts of examples is they don’t reflect the sort of code I tend to run into. Convert that example into something that’s a bit more realistic, and the braces cease to be an issue (particularly with something like the Rainbow Brackets plugin):

input.fold(inputIsEmptyError) { 
  _.entries.fold(entriesAreEmptyError) {
    validateEntries(allowFoo)(_)
  }
}
2 Likes