Maybe your answer is "with Optional" (or Option, or Maybe). We just choose to use union types and have "Nil | T" (Nil or T) be the same as "Option(T)" in other languages.
Maybe your answer is "with Optional" (or Option, or Maybe). We just choose to use union types and have "Nil | T" (Nil or T) be the same as "Option(T)" in other languages.
Maybe you are thinking of Java/C#, where reference types can also be null, but this is not true in Crystal. It's also in a way similar (but not quite) to Swift, where optional types are different than types that can't be null.
Option[T]'s are composable. For example, let's say we have a "get" method to get the value for a given key, whose type looks like:
get :: String -> (T | Nil)
If we were using Option[T]'s, it would look like: get :: String -> Option[T]
So let's say we have a map, and want to lookup a key (syntax is made-up): let m: Map[String,(Int | Nil)] = make_some_map()
let result: (Int | Nil) = m.get("some-key")
If result is nil, was the value of the key nil, or was the key not in the map?With Option[T]:
let m: Map[String,Option[Int]] = make_some_map()
let result: Option[Option[Int]] = m.get("some-key")
Here result will either be None, in which case the key wasn't in the map, or Some(None), which means the value of the key was None.So there is an observable and potentially useful difference between (T | Nil) and Option[T].
Sum types supported in the language such as in Ceylon is another one.
And yet another one is safe dereferencing operators (?.) such as in Kotlin.
Unions seem like more of a language-level feature, so I'm not sure you could abstract over them in the same way.
Nonetheless, I am thrilled that we are seeing more and more languages that don't have implicit nullability on any type.
With something that leaves "Nullpointer analysis" obsolete/useless.