Mark Needham

Thoughts on Software Development

Scala: Option.isDefined as the new null check

with 3 comments

One cool thing about using Scala on my current project is that we don’t have nulls anywhere in our code, instead when something may or may not be there we make use of the Option type.

Unfortunately what we’ve (heavily contributed by me) ended up with in our code base is repeated use of the isDefined method whenever we want to make a decision depending on whether or not the option is populated.

For example the following is quite common:

case class Foo(val bar:String)
val foo : Option[Foo] = Some(Foo("mark"))
> val bar = if(foo.isDefined) Some(foo.get.bar) else None
bar: Option[String] = Some(mark)

We can actually get rid of the if statement by making use of collect instead:

> val bar = foo.collect { case f => f.bar } 
bar: Option[String] = Some(mark)

And if foo is None:

> val foo : Option[Foo] = None
> val bar = foo.collect { case f => f.bar } 
bar: Option[String] = None

The code is now simpler and as long as you understand collect then it’s easier to understand as well.

Another quite common example would be something like this:

case class Foo(val bar:Option[String])
> val foos = List(Foo(Some("mark")), Foo(None), Foo(Some("needham")))
foos: List[Foo] = List(Foo(Some(mark)), Foo(None), Foo(Some(needham)))
> foos.filter(_.bar.isDefined).map(_.bar.get + " awesome")
res23: List[java.lang.String] = List(mark awesome, needham awesome)

Which we can simplify down to:

foos.collect { case Foo(Some(bar)) => bar + " awesome" }

When I was playing around with F# a couple of years ago I learnt that wherever possible I should try and keep chaining functions together rather than breaking the code up into conditionals and I think the same applies here.

There are loads of methods available on TraversableLike to help us achieve this.

Be Sociable, Share!

Written by Mark Needham

November 1st, 2011 at 12:58 am

Posted in Scala

Tagged with

  • You can make the code in your examples even shorter and more concise by not using collect with all those partial functions 🙂

    scala> case class Foo(val bar: String)
    defined class Foo

    scala> val foo = Some(Foo(“mark”))
    foo: Some[Foo] = Some(Foo(mark))

    scala> val bar = foo.map(_.bar)bar: Option[String] = Some(mark)

    scala> val foo: Option[Foo] = Nonefoo: Option[Foo] = None

    scala> val bar = foo.map(_.bar)bar: Option[String] = None

    scala> case class Foo(val bar:Option[String])defined class Fooscala> val foos = List(Foo(Some(“mark”)), Foo(None), Foo(Some(“needham”)))foos: List[Foo] = List(Foo(Some(mark)), Foo(None), Foo(Some(needham)))
    scala> foos.flatMap { s => s.bar.map(_ + ” awesome”) }res2: List[java.lang.String] = List(mark awesome, needham awesome)

    Have a look at Tony Morris’ Option cheat sheet (http://blog.tmorris.net/scalaoption-cheat-sheet/)

  • Oh neat that’s even better! Thanks for the link, that’s useful

  • Marconi Lanna

    There is a more extensive discussion about all Option methods here: http://blog.originate.com/blog/2014/06/15/idiomatic-scala-your-options-do-not-match/