1. Overview
One of the new features introduced in Scala 3 was the possibility of suppressing some occurrences of braces.
2. Optional Braces
Some braces can be replaced by an enforced indentation. Furthermore, poorly indented programs are flagged with warnings. This is called significant indentation, and it’s enabled by default. Using the compiler flag -no-indent, we can disable the feature.
2.1. Indentation Rules
There are two rules for well-indented programs. If either of those is not respected, the compiler will emit a warning. First, in a brace-delimited region, no statement is allowed to start to the left of the first statement after the opening brace that starts a new line:
if (x < 0) {
println(1)
println(2)
println("done") // error: indented too far to the left
Second, if significant indentation is turned off and we are at the start of an indented sub-part of an expression, and the indented part ends in a newline, then the next statement must start at an indentation width less than the sub-part:
if (x < 0)
println(1)
println(2) // error: missing `{`
These rules are not very strict on purpose. Their goal is to be helpful in pinpointing the root causes of errors related to missing braces.
2.2. Optional Braces for Class Definition
When defining a new class, trait, or object, we can also omit braces by using a colon (‘:’). The following are now valid definitions in Scala 3:
trait A:
def f: Int
class C(x: Int) extends A:
def f = x
object O:
def f = 3
enum Color:
case Red, Green, Blue
new A:
def f = 3
package p:
def a = 1
package q:
def b = 2
2.3. Special Treatment of case Clauses
Scala 3 also introduced some changes to the syntax of match/case clauses. Prior to Scala 3, when using pattern matching, we’d need to use braces:
import scala.util.Random
val x: Int = Random.nextInt(10)
x match {
case 0 => "zero"
case 1 => "one"
case 2 => "two"
case _ => "other"
}
But in Scala 3, we can now rewrite without braces:
import scala.util.Random
val x: Int = Random.nextInt(10)
x match
case 0 => "zero"
case 1 => "one"
case 2 => "two"
case _ => "other"
2.4. The end Marker
One of the potential issues raised when discussing this new feature is that it can make the code more difficult to understand when a given block ends. To solve this problem, Scala 3 offers an optional end marker:
def largeMethod(...) =
...
if ... then ...
else
... // a large block
end if
... // more code
end largeMethod
The end marker consists of the keyword end together with a specifier token. The specifier token can be one of the following:
- if
- while
- for
- match
- try
- new
- this
- val
- given
- <identifiers>
3. Conclusion
In this article, we saw one of the many new features introduced in Scala 3, optional braces. This language feature allows replacing some usages of braces by following specific indentation rules.