Search code examples
scalasyntaxpostfix-operator

scala "Illegal start of simple expression" in for comprehension with if


I am in the process of implementing a simple in-memory, Redis-like KeyValue store and experiencing a compilation failure on the if statement within the for comprehension following piece of code:

  /*
  Returns the specified elements of the list stored at key. The offsets start and
  stop are zero-based indexes, with 0 being the first element of the list to n. */

  def lrange(k: keyT, maxIdx:Int, minIdx:Int): List[valT] = {
    val l = lookup(k)
    //assert(maxIdx >= minIdx && maxIdx <= (l length) && minIdx >= 0, "invalid min or max argument. list size ")
    for {
      (x: valT, i: Int) <- l zipWithIndex      //tried without explicit typing
      if i <= maxIdx && i >= minIdx            //tried indenting if
    } yield x
  }

The editor (IntelliJ) shows no errors, but I receive the following build error when attempting to build and run tests.

[INFO] --- scala-maven-plugin:3.3.2:compile (default) @ DS4300Project3 ---
[INFO] .../Spring2019/DS4300/scala/DS4300Project3/src/main/scala:-1: info: compiling
[INFO] Compiling 3 source files to .../Spring2019/DS4300/scala/DS4300Project3/target/classes at 1550678144065
[ERROR] .../Spring2019/DS4300/scala/DS4300Project3/src/main/scala/com/rejevichb/homework3/KeyValStore.scala:70: error: illegal start of simple expression
[ERROR]       if (i <= maxIdx) && (i >= minIdx) //tried indenting if
[ERROR]       ^
[ERROR] one error found
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------

Specifically:

KeyValStore.scala:70: error: illegal start of simple expression

Any guidance or insight into what is going wrong here is appreciated, as the solution is not clear to me.


Solution

  • This is exactly the reason why you should use postfix operators with caution.

    for {
      i <- "a" zipWithIndex
      if true
    } yield i
    

    is parsed as

    for { i <- ("a" zipWithIndex if true) } yield i
    

    because the compiler attempts to interpret zipWithIndex as a binary infix operator, but then runs into if true, which is indeed not a simple expression.

    Workarounds:

    • just don't use postfix ops, use a period:

      for {
        i <- "a".zipWithIndex
        if true
      } yield i
      
    • add a semicolon to force zipWithIndex to be interpreted as postfix op:

      for {
        i <- "a" zipWithIndex;
        if true
      } yield i
      

      and then enjoy your feature warning:

      warning: postfix operator zipWithIndex should be enabled by making the implicit value scala.language.postfixOps visible.