3

At http://www.artima.com/pins1ed/builtin-control-structures.html#7.7, I see the following code

val a = 1;
{
  val a = 2
  println(a)
}
println(a)

where it says that the semicolon is required here, but why?

From the rule at http://www.artima.com/pins1ed/classes-and-objects.html#4.2 , I think the semicolon should be auto added since

  1. val a = 1 can be a legal statement.
  2. The next line begins with {, which I think can start a legal statement. (Since there's no compile error if I add the semicolon and separate the first two lines into two statements.)
  3. val a = 1 is not in parentheses or brackets.
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
pishen
  • 319
  • 3
  • 16

1 Answers1

5

Because it would be a legal call to apply:

implicit class RichInt(i: Int) {
  def apply(thunk: => Unit) = 33
}

val a = 1
{
  val a = 2
  println(a)
}
println(a)  // 33 !

1 { ... } is short for 1.apply {...}. Now apply is not defined for an Int by default, but as the implicit enrichment shows, it is perfectly possible.


Edit: The semicolon inference conditions are described in '§1.2 Newline Characters' of the Scala Language Specification. The inferred semicolon is called 'special token "nl"' in that text.

In general, three rules are given (summarised ex-negativo in this blog entry), and in your example they are all satisfied. The reason that the semicolon is still not inferred is given further down in the text.

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.

The relevant case of such an extra rule is the following:

A single new line token is accepted
– in front of an opening brace “{”, if that brace is a legal continuation of the current statement or expression ...

Example 1.2.2 shows the case of anonymous an subclass which I had referred to in the comment.

0__
  • 66,707
  • 21
  • 171
  • 266
  • Dose it means that `.apply` is always inserted before the semicolon inference take place? – pishen Sep 03 '13 at 15:52
  • Semicolon inference works by looking at the beginning of the next line. If that constitutes a valid method call, semicolon is _not_ inferred (but the method call consumed). E.g. `"schoko"\n.reverse`, or `"schoko"\n.apply(1)`. Since `apply` is often used to introduce custom control structure like methods, allowing the next line to start with an open curly brace is probably a good thing. On the other hand, using parentheses won't work. – 0__ Sep 03 '13 at 15:58
  • Think also about this case: `new Foo { def bar = 33 }`, depending on your style preference you might want to have a line break before the open curly brace, too. In that case, Scala will not infer `apply` but assume you are creating an anonymous sub class (which makes the most sense). Therefore, if you want to introduce a curly braces block on its own—for example, to isolate local variables—, you should always make sure that you have a blank line preceding it (or use semicolon, but I think the blank line is nicer). – 0__ Sep 03 '13 at 16:01
  • @pishen another example http://stackoverflow.com/a/18159362/1296806 . I think it's useful to review the few `nl` cases cited here. It seems like trivia but actually frees the mind a bit. – som-snytt Sep 03 '13 at 20:15
  • Extra blank line is good suggestion. Also, use `locally` from `Predef` for local stuff. – som-snytt Sep 03 '13 at 20:17
  • `locally`, hmmm, always new things to discover even after years :) – 0__ Sep 03 '13 at 20:22