When is semicolon mandatory in scala?

心已入冬 提交于 2020-02-24 14:39:24

问题


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?


回答1:


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?




回答2:


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.



来源:https://stackoverflow.com/questions/52017702/when-is-semicolon-mandatory-in-scala

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!