I am learning how to program in Scala and was being told that semicolon is optional in Scala. So with that in mind, I tried with the following nested block of code which does not have semi colon. However, it throws an error in the Scala REPL
scala> { val a = 1
| {val b = a * 2
| {val c = b + 4
| c}
| }
| }
<console>:17: error: Int(1) does not take parameters
{val b = a * 2
And the sample with semi colon worked perfectly fine.
scala> { val a = 1;
| { val b = a*2;
| { val c = b+4; c}
| }
| }
res22: Int = 6
Therefore it seems to me that semi colon is not really optional and is mandatory in some situations. May I ask in what situation the semi colon is mandatory?
I'll try to extract the essence from your example.
Consider the following code snippet:
{ val x = 1 { val y = 2 } }
To the compiler, it looks like syntactic sugar for
{ val x = 1.apply({ val y = 2 }) }
But the object 1
does not have an apply
method that takes blocks, therefore the compiler produces an error:
error: Int(1) does not take parameters
{ val x = 1 { val y = 2 } } ^
Contrast this to
object I { def apply(a: => Any): Unit = () }
{ val x = I { val y = 2 } }
This works, because I
now does have an apply
method.
To make the differentiation between these two cases a little bit easier, the compiler requires a semicolon in the first case.
Now one might wonder why a line break between val x = 1
and the {
is not converted into an inferred semicolon. I think the relevant quote from the spec would be this (1.2 Newline Characters) (most parts of enumerations omitted ([...]
), emphasis mine):
The Scala grammar [...] contains productions where optional
nl
tokens, but not semicolons, are accepted. This has the effect that a newline in one of these positions does not terminate an expression or statement. These positions can be summarized as follows:[...]
in front of an opening brace ‘{’, if that brace is a legal continuation of the current statement or expression,
[...]
Note that this quote covers only the case with a single optional line break. It does not hold for two or more consecutive line breaks, e.g.
scala> {
| val x = 1
|
| { val y = 2 }
| }
is valid, and { val y = 2 }
is parsed as a separate expression.
I guess the motivation was to allow embedded DSL's with syntactic sugar like this:
MY_WHILE(x >= 0)
{
println(x)
x -= 1
}
It would be really strange if one had to enclose each such MY_WHILE
-statement into an additional pair of round parentheses, wouldn't it?