A powerful Scala idiom is to use the Option
class when returning a value from a function that can be null. Simply stated, instead of returning one object when a function succeeds and null when it fails, your function should instead return an instance of an Option, where the instance is either:
- In the success case, return an instance of the Scala Some class
- In the failure case, return an instance of the Scala None class
Because Some
and None
are both children of Option
, your function signature just declares that you're returning an Option that contains some type (such as the Int
type shown below). At the very least, this has the tremendous benefit of letting the user of your function know what’s going on.
A simple Scala Option example
Here’s an example of how to use the Scala Option
idiom. This source code example is copied from the original version of the book, Beginning Scala:
def toInt(in: String): Option[Int] = { try { Some(Integer.parseInt(in.trim)) } catch { case e: NumberFormatException => None } }
Here's how this toInt
function works:
- It takes a String as a parameter.
- If it can convert the String to an Int, it does so, returning it as Some(Int).
- If the String can't be converted to an Int, it returns None.
If you're a consumer of this toInt
function, your code will look something like this:
toInt(someString) match { case Some(i) => println(i) case None => println("That didn't work.") }
Why Option is better than null
This may not look any better than working with null
in Java, but to see the value, you have to put yourself in the shoes of the consumer of the toInt
function, and imagine you didn't write that function.
In Java, if you didn't write the toInt
method, you'd have to depend on the Javadoc of the toInt
method.
(1) In the first case, if you didn't look at the Javadoc for the Java toInt
method, you might not know that toInt
could return a null
, and your code could potentially throw a NullPointerException
.
(2) In the second case, if you did happen to read the Javadoc, and did see that the code could return a null
, you might handle it like this:
Integer i = toInt(someString); if (i == null) { System.out.println("That didn't work."); } else { System.out.println(i); }
That code isn't any worse than the Scala Option
and match
approach, but you did have to read the Javadoc to know this was needed.
(3) In the third case, the programmer of the toInt
function could handle the NumberFormatException
differently, and return some other value besides null
, in this case, perhaps zero or some other meaningless number.
Even better!
If you're still not sold on using the Option/Some/None pattern instead of using null values -- I know I wasn't completely sold at this point -- let's see where Scala shines.
Let's assume you want to get the sum of a List
that contains a bunch of String
values, and some of those strings can be converted to Int
values, and some can't:
val bag = List("1", "2", "foo", "3", "bar")
Seems like the code should look really ugly, right? Wrong.
In Scala we can write a "sum" expression in just one line of easy to read code:
val sum = bag.flatMap(toInt).sum
Because (a) we've written toInt
to return either a Some[Int]
or None
value, and (b) flatMap knows how to handle those values, writing this line of code is a piece of cake, and again, it's easy to read and understand.
Now that shows how the Option/Some/None pattern really shines!
Java null versus Scala Option
If you've been through this scenario when using someone else's code, you know that at the very least (a) you need to read their Javadoc, and (b) if you don't, your code might throw a NullPointerException
. Compare this to the Scala Option idiom:
- You can see from the Scala function signature that the code returns
Option[Int]
, and knowing the Option/Some/None idiom, you know how to handle this situation. You can see this signature from your IDE -- there's no need to go look at the Javadoc for the function.
Getting exception information with Scala's Either, Left, and Right
One weakness of the Option approach is that you can't tell why something failed; you can't get access to the error/exception information. A solution to this is to use the Either/Left/Right classes, which are like Option/Some/None, except you can get access to the exception information. See my Scala Either, Left, and Right tutorial to see how to use Either/Left/Right, or the Try/Success/Failure classes introduced in Scala 2.10.
Summary: Scala Option, Some, and None
Even with this simple example, I hope you can see that the Scala Option/Some/None idiom can save you a lot of grief. Although in a simple example like this it doesn't seem to save you any code, I believe your code will be much more readable, and you'll avoid all the problems you can encounter when potentially dealing with null values being returned from functions.