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 A
s 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.
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.).
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
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
.
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.