Scala: how to handle many params that can be None

537 Views Asked by At

Right now I have many params that can be none, and I want to assign the whole expressiona default value.

Right now I'm doing things like

var name: Option[String] = None
var surname: Option[String] = Some("Smith")

val fullName:String = {
  name.map { name => 
    surname.map { surname => 
      surname + ", " + name
    }.getOrElse("unknown")
  }.getOrElse("unknown")
}

but it's a bit too verbose. I'd like to know what would be a more idiomatic and elegant way to handle it, ideally it would be something like (it's pseudo code, of course!):

val fullName = (name + ", " + surname).getOrElse("unknown")

or something similar...

(just avoiding the double .getOrElse would be great...)

3

There are 3 best solutions below

1
On

How about this

scala> val fullName = (for(n <-name;s <-surname) yield n + s).getOrElse("unknown")  
fullName: String = unknown
0
On

I've found this way:

val fullname = (name, surname) match {
  case (Some(x), Some(y)) => x + ", " + y
  case _ => "unknonw"
}

but it's still a bit verbose

1
On

You might want to learn a bit about applicative functors, as the same pattern can be used in all sorts of ways. Using scalaz, there is the applicative builder:

(name |@| surname)(_ + _)

What is going on is this:

(M[A] |@| M[B])(fabc) ~> M[C] //fabc is a function f: (A, B) => C

That is, the function f is being lifted into the realm of applicative functor M. This is particularly useful because it works with Option, Validation, Promise, List, Stream and many more. That is, just as you might use the expression:

(name |@| surname)(_ + _)

where name and surname are both Option[String], you could switch them to be ValidationNEL[Exception, String] or Promise[String] and the code would still do the exact same thing (appropriate to the higher kind being used). This is very powerful.