Search code examples
scalascala-option

Using Option with cleaner code


Apologies if this is a newbie question... In Scala I understand that it is preferred to use an Option rather than returning null when you have a function which returns an instance but could potentially return nothing. I understand that this makes it better with regards to safety, because you are not passing null references around, and risking NullPointerException somewhere down the line.

However, is there a cleaner way to handle options than using pattern matching? The syntax I end up using is the following:

val optObj : Option[MyObject] = myFunctionThatReturnsOption
optObj match {
  case Some(obj) => {
  //my code using obj
  }

  case None => _
}

In reality all this doing is the equivalent of the Java version:

MyObject obj = myMethodThatCanReturnNull()
if (obj != null) {
  //my code using obj
}

Is there some other way to avoid all this boilerplate in Scala when using Option instead of null references? All I want to do is execute a piece of code as long as the Option contains some object (i.e. is not None).


Solution

  • Use foreach, getOrElse and/or map if you want to work in a more consistent way. Here's some use cases and what I'd do:

     //I want to get a non-null value and I have a sane default
     val result = myOption getOrElse 3
    
     //I want to perform some side effecting action but only if not None
     myOption foreach{ value =>
       println(value toString ())
     }
     //equivalently
     for(value <- myOption){
       //notice I haven't used the "yeild" keyword here
     }
    
     //I want to do a computation and I don't mind if it comes back as an Option
     val result = for(value <- myOption) yield func(value)
     val equivalent = myOption map func
    

    The third example will use map in both cases.

    It gets really interesting when you can mix and match things in a "for comprehension" (Google term.) Let's say that func also returns an Option but I only want things working in specific cases:

     val result = for{ 
       value <- myOption if value > 0
       output <- func(value)
     } yield output
    

    Now I get back an Option but only if myOption contained an integer that was greater than zero. Pretty nifty stuff, no?