10/8/11

Yes, Virginia, Scala can save you from Null Pointer Exceptions.

First, Virginia, let me tell you that I don't know why everybody in the Scala community is writing to to you, I guess is because you're curious and want to learn about it, or maybe you know where to find the  mythical "average programmer". But I digress...

Let's focus on the subject of this post: how you can prevent null pointer exceptions with Scala. Suppose you have your tidy Scala code in functional flavor with all the fixes, and you need to do a series of calls to a Java library, where each value depends on the previous value: let's say you want to call functions A,B,and C.
  val x=A(in)
  val y=B(x)
  val z=C(y)

(or C(B(A(in))) if you like )

Now, is common in Java to return null when no value can be returned or even throw an exception if something goes wrong. How we prevent that? The naive approach will be to chain the ifs:


   val x=A(in)
   if (x != null){
       val y=B(x)
       if (x != null){
         val z=C(y)
       }
   }

I don't know you, but for me that style doesn't cut it anymore, is too verbose! And now our flow is littered with null checks, obscuring the purpose.
So, what we can do? I know! Let's use Scala's Option and write a small function that returns "Some" value or "None" if we got null or something wrong happened:



Nothing fancy here, Option(x) will evaluate x and return Some(x) if it has a value or None if is null. The only noteworthy thing here is in the signature: it defined as " x:=> T " that roughly means "any function that returns something of type T", so x will be evaluated when we actually use it and not when we call the function, otherwise we risk getting the exception before entering the try block.

 Ok, so now we wrap every function call with our unsafeCall function, but now we have a problem, the types don't match! We can't just chain the calls, we need to extract the value from the Option first!
We can try with pattern matching:

  A(x) match {t
    case None => _
    case  Some(y) => B(y) match {
      case None => _
      case  Some(z) => C(z)
    }
  }

But it looks clumsy and we don't gain much compared to the "if not null" version, what we can do?
Let's take a step back and look at the types: we want to chain a series of function with T=>Option[T] ... does it ring a bell? What if we write as T=>M[T] ? If you've said the M-word, bingo!
Some[_] is a monad, and that means we can use Scala's "for" notation.
Let's tie everything together in one example:

ADENDUM: This is a toy example for illustrative purposes. I guess I should have left out the exceptions, otherwise is almost the same result as surrounding everything with a try/catch. Also, is an exception happens, we want to know what happens, for that Either is more suitable than Option (I'll leave that for another blog post). Still, when you need to chain a series of functions that return Some/None, for comprehensions gives you a nice sugar ;)

10 comments:

Channing Walton said...

Fyi, you could replace the unsafe method with scala.util.control.Exception.catchAll

(maybe you just wanted to show how that worked anyway)

Viktor Klang said...

Swallowing Errors isn't really a nice practice, no?

Lars said...

Didn't you mean T => Option[T] and Option as a monad, instead of Some[T]?

hohonuuli said...

See also http://hohonuuli.blogspot.com/2010/07/safe-dereference-operator-in-scala-ive.html

kaja47 said...

I think, it would be better to use `a <- Option(A(i))` instead of `a <- unsafe(A(i))`. Option(x) doesn't swallow exceptions but wraps nulls to None and any other value to Some(x).

Unknown said...

@Lars Fixed, thanks

@Viktor I'll clarify that, I plan to follow with a post using Either to capture what really happened.

@kaja47
Yes, that's cleaner, I wanted to throw exceptions in the mix...

reddy said...

hello could you please post about software process management supplement specification for track and locate system. thank you

Techsaga Corporations said...

Indian business consultancies focus on the facility providing distinctive operational competency to the unique business needs reading them through business strategy, changes in IT landscape, current pin-points, etc.

emailtaai said...

Techsaga is Software development company in Noida. it providing end to end software solutions to customers globally. Techsaga are specialized in every vertical of industries and deliver quality solutions using the latest technologies.

Stacy Baker said...

You might ask: “Why do diet pills work for me?” You might say: “My stomach is always full. So why do I always crave for food?” You might ask: “Why is my diet not working?” You might have tried to lose weight but there is no weight loss, or maybe you are not losing any weight at all. The problem might be the foods you have in your diet...Read also...