Why did other languages not incorporate the same s...
# announcements
d
Why did other languages not incorporate the same system of nullable type to handle nullability like kotlin? It seems so intuitive and obvious to be done in the first place Are there any downsides of this approach that are not immediately obvious?
but fundamentally, according to Hoare, it's because "they were so easy to implement"
s
The main difference between a
T?
and an
Optional<T>
is that
T
is assignable to a
T?
but a
T
is not assignable to an
Optional<T>
. That is what I like about
T?
, nullable types. Without that assignability, such as with
Optional<T>
, you’d have to use things such as
map
and
flatMap
, etc to handle transformations
r
Optional is still great if you have an optional
T?
s
E.g
nullableValue?.something()?.name
vs
optionalValue.flatMap { something() }.map { it.name }
d
yeah I am aware of billion dollar mistake, but it's been 20-30 years since it was incepted, yet languages continued and still do use nulls
s
But treating it as a separate type is the big difference here. In Kotlin a
null
value is of type
Nothing?
and that makes dealing with null values easier.
d
and that's why I am asking, nullable type is more flexible than optional monads, but nobody seem to follow this approach
why?
b
There's also a talk floating around on the interwebs somewhere about "wouldn't it be terrible if we forgot all of the computer science we've learned in the last 50 years" and proceeds to demonstrate ideas implemented in the 60s, 70s, and 80s that have yet to make it into practice
👍 1
s
It depends. If you have a monadic framework, like Arrow, using
Optional
maybe preferred, since you’ll be using
Either
,
Try
, etc as well. The ‘Optional’ fits in this monadic framework, while
T?
may not….
b
"nullable type is more flexible than [Maybe]" I'm skeptical about that because I think T? is isomorphic to Option<T>
and T? doesn't have the benefit of flatMap comprehensions so any sort of applicative or monadic structure over multiple Options becomes a rat's nest of braces
s
If you are not using monadic frameworks, using
T?
is preferred over a (homegrown)
Optional<T>
, in my opinion. If you use frameworks such as Arrow, and you want to make full use of their functional/monadic properties, then use `Optional<T>`/ Most folks I know never use(d) functional/monadic frameworks. Using
T?
is a great solution to deal with nullability
b
agree @streetsofboston
s
If I shout ‘comprehensions’ here at work, 99% of my team members’ eyes will glaze over 🙂
r
Writing an extension function for Optional which is only visible for Optional<T> and not for
T
is easy, doing the same for
T?
and
T
is currently not even possible
to name a drawback of
T?
(or rather the lack of lower-bounds in Kotlin)
s
But the other way is possible, writing an extension-function visible by
T
but not by
T?
🙂
r
sure, same for
T
and not by
Optional<T>
s
But you’re right, Robert. That can be a drawback. I’m still wondering what actual use case that maybe useful for….
r
"hello".isNullOrBlank()
does not make sense
should be defined only for
String?
but not for
String
s
The
..orBlank()
part makes sense…:
"".isNullOrBlank()
k
Same for
?:
actually, it should not be "defined" for
T: Any
.
r
but not if you have already
isBlank
IMO
s
@karelpeeters Does the IDE give you a warning if you do a
?:
on a
T: Any
? I think it does, but i’m not sure….
k
Yes the IDE issues a warning. That's my point, it's not an actual language feature. There should also be a warning for
isNullOrBlank
and possibly many other user-defined functions.
And then you need a language feature, either lower bounds or something else.
(for the record: I don't think it's that important but it is an advantage of
Optional<T>
over
T?
)
a
I find Optional model a little nicer. For instance, let's say I have a function that returns an entity from a data source. I want to call that function, transform the entity and log a message if the result was empty. In Kotlin:
Copy code
val u = ds.findUser(userId)
if (u == null) log.debug("it was empty")
return u?.let { doSomething(it) }
in Scala:
Copy code
ds.findUser(userId).map(doSomething).getOrElse { log.debug("it was empty"); None }
Scala code from my personal view in this case is more concise, expressive, explicit, you don't use or see
null
at all in the code.
Or slightly different, simpler example, Kotlin:
val mapped = value?.let { transformValue(it) } ?: defaultValueIfValueIsNull
Scala:
val mapped = value.map(transformValue).orElse(defaultValueIfValueIsNull)
h
That kotlin version could look almost identical to the scala version with the introduction of a couple of extension functions