简体   繁体   中英

When is semicolon mandatory in scala?

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, eg

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?

Adding to Andrey's answer, it's rare that you write code like this in idiomatic Scala, but, when you do, you should use locally :

{
  val a = 1
  locally {
    val b = a * 2
    locally {
      val c = b + 4
      c
    }
  }
}

This case is exactly why locally exists.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM