Naive question about Option

I have never been a fan of Optional in Java. In Scala, I may be mistaken, but it looks like Option is implemented in a similar way by boxing it. Wouldn’t it be easier if Scala used Option to create a polymorphic type with a null value (None) as a bottom element of the domain? Or would that be implemented the same way as boxing it anyway?

Take a look at the sources (my comments added):

// Covariant on `A`, so ...
sealed abstract class Option[+A] ... 
// ... the standalone object is indeed substitutable for
// any `Option[A]`, as `Nothing <: A` for all `A`.
case object None extends Option[Nothing] ... 

So in a sense, None is a bottom element, only it doesn’t slot under Some[A], rather under Option[A]. I think that’s the right way of thinking about it, actually mapping to the underlying As and a null value is fine as an implementation trick, but doesn’t map on to the intended three types.

An absence is not a special case of a presence.

I recall that F# optimised out its option boxes when it could for reference types, using a raw A for Some and a null reference for None. It wouldn’t surprise me if Scala does that too behind the scenes when it can, perhaps the compiler folks will weigh in …

I’m under the impression that functional programming starts at a different place, closer to an ideal. Imagine a world without null - where Sir Tony Hoare hadn’t made his “billion dollar mistake” (see Tony Hoare - Wikipedia). Everything has some assigned value from the start so you never need null .

Option/Some/None gives you a zero-or-one collection, which turns out to be useful in a lot of contexts. It is pretty natural to pay for a new instance of a collection to capture that minor complexity. There’s exactly one None, so you only pay when you have Some interesting thing.

One of the common problems Option solves is using a Java or C API where null can mean None (instead of just “broken”). You need a type-safe way to pay for Sir Hoare’s mistake, and keep null pointer exceptions or worse out of your world. Option is a great hammer to pound down that nail; you only have to remember it once and the compiler reminds you to swing that hammer whenever the Option pops up.

You can still use var possiblyNull:Thing = null with sprinkles of if(possiblyNull != null) where you prefer. When you care about performance - and a profiler blames a hot spot on allocating Some(thing)s - then maybe it is worth the effort to maintain null checks … but it isn’t as fun.

2 Likes

Wouldn’t it be easier if Scala used Option to create a polymorphic type with a null value (None) as a bottom element of the domain? Or would that be implemented the same way as boxing it anyway?

There are some experiments to have a boxless option that, due to many reasons (in part historical, in part because there are some caveats with that). It might still happen in the future, but it will probably take a long time to make it to the stdlib.

So, that point is valid, but I think it’s not as important as you might think (as I’ll discuss below).

It wouldn’t surprise me if Scala does that too behind the scenes when it can

Unfortunately, I’m pretty sure Scala doesn’t do anything like that. I think the backend (JVM, Inteflow+LLVM, GCC+V8,…) might sometimes be able to optimize away the box, but I wouldn’t count on it for performance sensitive code.

So, in general, you would use null in performance sensitive code, but ideally never expose that to the end user of your function/library, by converting to Option once the performance sensitive part was over.

Having that out of the way:

I have never been a fan of Optional in Java.

I understand where you are coming from, because I am also not a big fan of Java’s Optional (in it’s current state), however I love Scala’s Option.

I believe there are a few differences between Optional and Option but, to me, the main thing that makes Option much better than Optional is related to the ecosystem: Option it has been part of the Scala stdlib since the start, so it’s used everywhere, while Optional is barely used in the java stdlib due to compatibility guarantees.

This means that you can reliably rely on Option to know if something is optional or not, which is incredibly freeing. In Java you always have to second guess if something is null or not, making Optional code a bit of a mess (wrap this null here, then convert to null again…).

Also, the Scala API has a bit more helpers and is less verbose, which also helps a bit to keep Optional code simple. (See some examples in Scastie - An interactive playground for Scala.).

2 Likes

here’s an proof-of-concept of unboxed optional values in scala: GitHub - sjrd/scala-unboxed-option: A type-parametric unboxed Option type for Scala

4 Likes

Long story short, one of the main issues with a naive unboxed implementation is that you can no longer see the difference between e.g. Some(None) and None which, believe it or not, is still an important property of Option. The implementation by sjrd that @tarsa posted solves that issue by adding a minimal amount of boxing only when it can’t be avoided. Note though that even there primitives like Int will still be boxed into java.lang.Integer.

1 Like

It seems we have a packaged library at our disposal now:

kyo/kyo-data/shared/src/main/scala/kyo/Maybe.scala at main · getkyo/kyo · GitHub.

There’s an entire world of stuff in that project. Not just batteries included, but a wind farm, hydroelectric dam, solar array and a nuclear power plant too.

1 Like