17

On compiling the following code with Scala 2.7.3,

package spoj

object Prime1 {
  def main(args: Array[String]) {
    def isPrime(n: Int) = (n != 1) && (2 to n/2 forall (n % _ != 0))
    val read = new java.util.Scanner(System.in)
    var nTests = read nextInt // [*]
    while(nTests > 0) {
      val (start, end) = (read nextInt, read nextInt)
      start to end filter(isPrime(_)) foreach println
      println
      nTests -= 1
    }
  }
}

I get the following compile time error :

PRIME1.scala:8: error: illegal start of simple expression
    while(nTests > 0) {
    ^
PRIME1.scala:14: error: block must end in result expression, not in definition
  }
  ^
two errors found

When I add a semicolon at the end of the line commented as [*], the program compiles fine. Can anyone please explain why does Scala's semicolon inference fail to work on that particular line?

missingfaktor
  • 90,905
  • 62
  • 285
  • 365
  • 1
    Just off-the-topic, `2 to n/2` can be replaced with `2 to Math.sqrt(n)` — it is the canonical solution, although I don't know if it will provide better performance (I think, it won't). – BorisOkunskiy Feb 14 '10 at 07:57
  • i know this is an OLD thread, but could you explicitly put the semicolon after the `read nextInt` line? or is this a problem because there is no argument provided to `nextInt`? – Ramy Aug 05 '11 at 02:32
  • @Ramy: Read the answers. – missingfaktor Aug 05 '11 at 06:22
  • @missingfaktor: it's actually at the bottom of your question. (+1 - thanks) – Ramy Aug 05 '11 at 15:20

3 Answers3

19

Is it because scala is assuming that you are using the syntax a foo b (equivalent to a.foo(b)) in your call to readInt. That is, it assumes that the while loop is the argument to readInt (recall that every expression has a type) and hence the last statement is a declaration:

var ntests = read nextInt x

wherex is your while block.

I must say that, as a point of preference, I've now returned to using the usual a.foo(b) syntax over a foo b unless specifically working with a DSL which was designed with that use in mind (like actors' a ! b). It makes things much clearer in general and you don't get bitten by weird stuff like this!

oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449
  • i know this is an OLD thread, but could you explicitly put the semicolon after the read nextInt line? or is this a problem because there is no argument provided to nextInt? – Ramy Aug 05 '11 at 02:32
11

Additional comment to the answer by oxbow_lakes...

var ntests = read nextInt()

Should fix things for you as an alternative to the semicolon

ColinHowe
  • 473
  • 2
  • 10
8

To add a little more about the semicolon inference, Scala actually does this in two stages. First it infers a special token called nl by the language spec. The parser allows nl to be used as a statement separator, as well as semicolons. However, nl is also permitted in a few other places by the grammar. In particular, a single nl is allowed after infix operators when the first token on the next line can start an expression -- and while can start an expression, which is why it interprets it that way. Unfortunately, although while can start a expression, a while statement cannot be used in an infix expression, hence the error. Personally, it seems a rather quirky way for the parser to work, but there's quite plausibly a sane rationale behind it for all I know!

As yet another option to the others suggested, putting a blank newline between your [*] line and the while line will also fix the problem, because only a single nl is permitted after infix operators, so multiple nls forces a different interpretation by the parser.

Matt R
  • 9,892
  • 10
  • 50
  • 83