@jxtps Thank you for writing up your proposal. I’ll start with answering a few individual points that arose in the discussion.
This is normal. It is analogous to the fact that Option(null) != Some(null)
, but Option(1) == Some(1)
.
Note that USome(null) == null
. In general, USome(x) == x
for all x
.
No you can’t do any better than unboxed-option, because the implementation of unboxed-option is already basically what an opaque type would provide. It’s just very hard to correctly implement without opaque types baked into the language, but in this specific case it can be done.
I see this thread as an opportunity to remind people of one very important thing: Option
is not a better way to deal with null
! It is a better way to deal with optional values. null
itself is a poor way to deal with optional values. It is not type parametric, as you cannot represent an optional value of a type that can itself hold null
. I have said that countless times, and for the most part I have stopped trying to explain this. But this thread might be the first time someone actually suggests this in a post including “SIP” in the title, so maybe it’s worth trying one more time.
For that reason, aliasing ?[A]
to A | Null
is a terrible idea. It’s a very common idea, unfortunately. Even Martin wanted to do that. The big problem if you do that is that it will be easier to write A?
than Option[A]
, so people will write A?
. But A | Null
is not type parametric, and that will cause countless obscure bugs. We’ll have regressed to Java-like unsafety about null
, perhaps even worse than Java because of the false sense of security in doing so. If at all, A?
should desugar to Option[A]
. Yes, Option
boxes, but at least it is type parametric.
And that brings me to the original proposal.
This kind of “if it has this type shape, do that, otherwise do that” has no precedent in Scala, and it would be dangerous. Because if I have an A
and I use this operator, I don’t really know whether null
is supposed to be considered as “empty” or as “valid value that happens to be null
”. This operator would end up turning too many null
s into None
. It’s bad enough that Option(x)
is named as it is (it should be Option.fromNullable(x)
or something like that), but giving it a short alias like that is going to make it be used even more. But this constructor is completely overused already. How many have I seen people writing Option(x)
instead of Some(x)
?
So, at the very least we should scrap everything that implicitly converts from A
to Option[A]
in the proposal. If we do that we’re left basically with
a: String?
as a parameter is something that- at call site, can be given a
String
, or can be not given at all. - at call site it would also make sense to allow passing
x: _?
whenx
is anOption[String]
, which corresponds tox: _*
for varargs whenx
is aSeq[String]
. - at definition site, inside a method,
a
is anOption[String]
.
- at call site, can be given a
- an “Elvis” operator
x?.f
, which is actually nothing more than syntactic sugar forx.map(_.f)
When you look at it that way, the two main bullets are really separate proposals. The second one probably wouldn’t hold its ground, because it is redundant wrt. for comprehensions, and does not provide a solution for the flatMap
case. The first bullet is defensible.