Search code examples
scalafor-comprehensionscala-option

How to yield None in for-comprehension if some condition meets


I'm experimenting with for comprehension and wrote the following code:

object Main extends App {
    val resultOption: Option[Int] = 
    for{
        i1 <- opt1
        i2 <- opt2
    } yield {
        if(i1 + i2 > 10) null.asInstanceOf[Int]
        else i1 + i2
    }

    println(resultOption) // <---- Here

    def opt1: Option[Int] = //some computations
    def opt2: Option[Int] = //some computations
}

IDEONE working example

I wanted the resultOption to be None in case the condition is met, but Some(0) returned. I looked at the compiled code of the yield block and what we have here is:

Code:
   0: aload_0
   1: getfield      #25                 // Field i1$1:I
   4: iload_1
   5: iadd
   6: bipush        10
   8: if_icmple     18
  11: aconst_null
  12: invokestatic  #31                 // Method scala/runtime/BoxesRunTime.unboxToInt:(Ljava/lang/Object;)I
  15: goto          24
  18: aload_0
  19: getfield      #25                 // Field i1$1:I
  22: iload_1
  23: iadd
  24: ireturn

At 12: we call BoxesRunTime.unboxToInt(null) which indeed returns 0. The question is how to yield None in case of i1 + i2 > 10.


Solution

  • From the asInstanceOf-codesmell alone it should be obvious that it doesn't work that way. You have to move the filtering step into the generator part of the for-expression:

    for{
        i1 <- opt1
        i2 <- opt2
        if (i1 + i2 <= 10)
    } yield i1 + i2
    

    Note that inside the for-comprehension, the parentheses in (i1 + i2 <= 10) can be omitted.