Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: March 18, 2024
In Scala 3, significant indentation is a feature that’s enabled by default, streamlining our code for better readability. In this tutorial, we’ll see how this feature allows us to define code blocks using braces or relying solely on indentation.
With significant indentation, we’re now able to leave some braces out. Furthermore, poorly implemented programs are flagged with warnings when using them or errors when leaving them out.
We can now write the same code with braces:
if (house == "Gryffindor") {
println("Ten points to Gryffindor!")
println("Well done, Harry!")
}
Or we could write it without them:
if (house == "Slytherin")
println("Ten points to Slytherin!")
println("Excellent, Draco!")
When using significant indentation, the compiler enforces a rule that helps us maintain well-structured code. Specifically, in a brace-delimited region, no statement can start to the left of the first statement right after the opening brace.
The compiler issues a warning on any code that breaks this rule:
if (house == "Hufflepuff") {
println("Ten points to Hufflepuff!")
println("Great job, Cedric!")
println("Oops!") // Compiler warning: indented too far to the left
}
-- Warning: indentation.scala:6:4
6 | println("Oops!") // Compiler warning: indented too far to the left
| ^
| Line is indented too far to the left, or a `}` is missing
1 warning found
These warnings are incredibly useful because they help us quickly identify and correct issues related to indentation, thereby reducing the likelihood of bugs and improving code readability.
Sometimes, we may disable significant indentation, such as when transitioning from Scala 2 or working on projects that follow a different coding style. The -no-indent compiler flag allows us to do just that.
By using -no-indent, we revert to the Scala 2 style, where braces are mandatory for defining code blocks:
if (character == "Luke Skywalker") { // This is now mandatory
println("May the Force be with you.")
println("You're a Jedi, Luke.")
} // This is also mandatory
When significant indentation is turned off, another rule comes into play. Some expressions, like if, allow us to have a code line in each branch, but the following line must have less indentation, or the compiler reports an error.
This means some code that used to work in Scala 2 will fail to compile in Scala 3.
For example, the following code works in Scala 2, printing “After If!” but fails with a compiler error in Scala 3:
val a = 0
if(a < 0)
println("Inside If")
println("After If!") // Compiler error in Scala 3: missing `{`
Disabling significant indentation can be helpful in specific scenarios, such as integrating Scala 3 code with a Scala 2 codebase.
However, it’s crucial to understand that turning off this feature can result in noisy builds due to the introduced warnings and errors. Therefore, we should consider the pros and cons before using the -no-indent flag.
When defining a new class, trait, or object, we can omit braces 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
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"
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:
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.