https://kotlinlang.org logo
#arrow
Title
# arrow
m

mitch

10/12/2023, 12:48 PM
Cross posting perhaps something worth sharing to arrow crew about nested nullability. I asked #language-proposals about it and got a positive response from JB team.. 🙌https://kotlinlang.slack.com/archives/C0B9K7EP2/p1697071770167569?thread_ts=1697070559.620599&cid=C0B9K7EP2https://kotlinlang.slack.com/archives/C0B9K7EP2/p1697103827934389?thread_ts=1697070559.620599&cid=C0B9K7EP2 I also left a comment in the union type KT ticket https://youtrack.jetbrains.com/issue/KT-13108/Denotable-union-and-intersection-types#focus=Comments-27-8229776.0-0
nothing seems to be set in stone yet... But it's quite exciting. I really really hope optionality can finally be adopted in Kotlin proper. (I mean Swift already have those for a very long time) One of the reasons why Arrow's
Option<T>
was godsend is because it doesn't have the nested nullability problems. We don't have to think about it when we write code.
y

Youssef Shoaib [MOD]

10/12/2023, 2:21 PM
If you want to see an (impractical) but slightly more performant version of arrow's Option, take a look at this PR,
s

simon.vergauwen

10/12/2023, 2:30 PM
I saw your ticket, but I doubt Kotlin is ever going to adopt
T | Null
for
T?
it'll probably open a can of worms with all existing code, and probably requires a bunch of special changes to support the current
?:
syntax only for
| Null
. Also
T | Null | Null <~> T | Null
, so does it really solve the nested nullability issue? Perhaps
(T | Null) | Null
🤔 cc\\ @Alejandro Serrano.Mena Did you ever get to test that branch against Jackson, or Project Reactor @mitch?
👀 1
I still think unions would be great though, quite some use-cases for it. Similar to tuples. Anonymous sum and product types quite useful, but probably prone to abuse like everything 😄
y

Youssef Shoaib [MOD]

10/12/2023, 2:32 PM
Mentioned this elsewhere, but I'm pretty sure the Kotlin team is leaning more towards this style: https://kotlinlang.slack.com/archives/C0B9K7EP2/p1697119729115219?thread_ts=1697070559.620599&amp;cid=C0B9K7EP2
👍 2
s

simon.vergauwen

10/12/2023, 2:32 PM
That'd be a huge improvement already!! I have a bunch of
val res: Any? = EMPTY
in libraries now, and it's super ugly
Having
A?
as
A | None
would solve some nullability issues when working with Java too though. Some libraries don't allow
null
as a value
a

Alejandro Serrano.Mena

10/12/2023, 3:07 PM
In all formality, union types do not solve this. One important property of such types is that A | B | B must be indistinguishable from A | B, so if you translate T? as T | Null you would not be able to distinguish T? from T??, by design
🧙‍♂️ 1
The more I look into this, the more I think that the problem is conflating nullable types with a potential missing element in the collection
2
s

simon.vergauwen

10/12/2023, 3:10 PM
That's what my understanding was as well. It relates to
A | B
and
B | A
. > The more I look into this, the more I think that the problem is conflating nullable types with a potential missing element in the collection It goes beyond that, it's bitten me in non-collection generic code as well. The problem is always using
null
as an "error" signal in generic contexts.
2
m

mitch

10/13/2023, 1:18 PM
@simon.vergauwen @Youssef Shoaib [MOD] ohh yes I remember testing that branch. Reactor works with it last time I checked. Jackson wasn't able to deal with value classes yet when I tested it. There might be some improvement around those since then I'll have to double check.
@Alejandro Serrano.Mena I believe so plus what Simon mentioned as well.. the problem with null is, null is a value that is not a value. Because of that using nulls as both flags for nullability and absence is just simply not going to work.. as you've rightly pointed out about how the type union becomes indistinguishable
T | null | null == T | null
. Boxing null into a value type
Option<T> == (T | null)
is also going to suffer the same fate i'm afraid... it means we would have an unrepresentable type when T is nullable I.e.
Option<T?> == (T | null | null) == (T | null)
In other words, option as value class will make the Option type unsound for
T?
I.e. it breaks identity law for any nullable type... By contrast, swift and current arrow option uses tagged union of
Option<T> = Some(T) | None
which is well behaved for any T and T? E.g.
Option<T?> = Some(T | null) | None
Observe how it nests elegantly as well
Option<Option<T>> = Some(Some(T) | None) | None
which simplifies to
Some(Some(T)) | Some(None) | None
The reason why nulls doesn't propagate in reactor / rxjava is similar too right, because null in these frameworks are used as a special value that is conflated to signal empty observable or mono..