I was talking to one of my co-ops today about what an
Option in Scala is, and it reminded me that I’ve been meaning to blog about option types. Plus Mom has been bugging me for another good coding blog post since I’ve been a little quiet lately. I’ve just been having too much fun writing SNMP4S which no one, I mean NO ONE, not even Mom, will ever use.
So what is
Option[T]? There are several ways to think of it. One way is to consider it a
Collection[T] just like
List[T] but with size/cardinality 0 or 1. That is, it is either empty, or full. You can iterate over it (either zero iterations or one iteration), map over it, reduce it, etc. It is implemented with a small hierarchy of classes. If it is empty, then it is a
None. If it is not empty/full, it is a
Some[T]. You can certainly see that
Option[T] is an abstract base class and
Some[T] are the only two concrete sub-classes.
Okay… why? The idea is you want expose fields, arguments, etc as not being required and hence optional. My initial thought is that it’s no better than what Java already provides with
null. That is, you have the object or you have
null. Now instead of this code:
String str = map.get("key");
if(str != null)
I now have this code:
val str:Option[String] = map get "key"
It’s basically the same amount of code. It also doesn’t eliminate the possibility of getting a runtime exception. Just as dereferencing
null produces a
get() on a
None throws a
NoSuchElementException. I just thought they were taking the null pointer problem and moving it, hence not avoiding Tony Hoare’s “billion-dollar mistake”. I’d love to see languages disallow null pointers altogether, but this wasn’t solving that problem in my mind.
But, I wouldn’t be writing this post had I not seen that
Option[T] is FAR superior to using
null. How so? Well consider the differences in signature for
Map[K, V].get(key:K) between Java and Scala:
V get(Object key)
get(key: K): Option[V]
Without looking at the documentation, which of these two might return a
None? Yeah, the Scala one. The
Option type is a big red flag that says “This thing possibly has an undefined value, so you better handle that.” Don’t get me wrong, they both say that in the respective docs:
<Java>Returns: the value to which the specified key is mapped, or null if this map contains no mapping for the key
<Scala>Returns: an option value containing the value associated with key in this map, or None if none exists.
The explicit declaration that a type could be undefined is a fantastic idea. The caller of the API is explicitly warned in the code that
None is a distinct possibility and any calls that just return
T are guaranteed to be legit instances of
T (WARNING: Not true for Scala, unfortunately. In order to interop with Java libraries, Scala also has a
null. If only Java had gone the option route!). Hence it’s not even possible for the call to return something dereferenceable unless the creator of the API explicitly advertised that possibility. It does in fact just move the null reference problem, but it moves it to the type system which I’m finding more and more is a good idea.