What is the goal of kotlin.nullable package?


#1

Hi.

As you all know, Kotlin has a great null-safe type library. It’s unique in Java world. It was a huge effort to design, implement and polish the whole thing:

  1. It is completely safe and has magnificent IDE support
  2. It is extremely simple to learn and use - it has nearly-zero menal overhead
  3. It is as fast as possible in JVM with zero runtime overhead
  4. It just works.


Great!

Imagine a new developer who wants to learn Kotlin. One of the most common programming exercises is to reverse the string. Let’s open IDEA and type in this simple code:

val something = "ABC"
print( something.reverse() )

It looks good, sounds reasonable, compiles and runs. IDE support! Type inference! Null-safety! Sweet Kotlin.
The program prints ABC instead of CBA. Surprise!

In desperate panic, the first line gets changed a little bit:

val nothing = null
print( nothing.reverse() )  // what the f… function is called here?

It looks bad and sounds crazy. Nevertheless the program still compiles, runs and prints… null
Surprise!
Why is it allowed to use simple dot with nullable variable? Where is my NPE then? Null-safety magic? Is it my coffe or other exotic cultures?..

The truth is, there’s no reverse() method for String at all. Surprise!
At this moment our brave but unfortunate ealy adopter uninstalls IDEA and open his blog to spread his strong feelings.

FAIL?

It turns out that there is no “if” statement in Haskell (for Great Good).
Therefore, well-educated Haskell programmers have to use empty collections instead of null values. Okay, why not.
Therefore, well-educated Scala programmers use Option objects in Scala code. Okay, still better than NPE.
Therefore, well-educated Kotlin programmers may use kotlin.nullable and do some kind of the same magic. Although there is an “if” expression in Kotlin.
// yet, all Java libraries may return null values (ignorant Scala programmers could too, if they existed), so the problem is still not solved in Scala

Kotlin doesn’t have Option by design.
So, here is my first question: Why Kotlin programmers may want to threat nullable values as Collections at all? There is already a better, nearly perfect way to deal with it!

Now we have to go deeper. All calls to monadic functions for Collections like map, reduce or reverse are statically resolved during compilation. That’s the ideology.
Therefore, whenever Any?.reverse() is used, it definetely means that something is wrong with programmer’s expectations. This will be a great place to put a compilation warning, if not error.

Assuming that there is a great reason for this package, I have another question: Why all those transformations are done implicitly?
In my opinion, this goes against Kotlin’s deep philosophy: why am I forced write 5.toFloat(), but can write null.reverse() just on the next line?


#2

If a real-world example is needed, just type "abc".flatMap, wait 1 second for a pop-up and press space. Done.

Now you have “import kotlin.nullable.flatMap” automatically and silently added to the top of your file.
Since this moment, flatMap is broken for the next hour of painful desperation - type-checker errors and IDE hints are extremely misleading until this import is removed.


#3

Just to fix things, I propose:

  1. Completely remove kotlin.nullable package altogether
  2. Those who want to write code in Haskell-style instead of Kotlin-style, may implement a single static method:

public inline fun <T: Any> T?.toOption(): Set<T> = if (this == null) Collections.emptySet() else Collections.singleton(this)

and enjoy all great things already made for sets, collections and iterables.

For marketing reasons, JetBrains might want to include this function into standard library. Instead of the whole package.


#4

Agree with you that it's reasonable to have some explicit conversion to collection in kotlin to make things more transparent. I've create an issue KT-3192 for this. Thank you for the feedback. http://youtrack.jetbrains.com/issue/KT-3192