Last active
September 4, 2017 18:41
-
-
Save dcastro/69cecd670ccd78ab0ff33626f33db3b2 to your computer and use it in GitHub Desktop.
Nested nullables in Kotlin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// A function that takes an instance of `T` and returns a nullable `T?` | |
fun <T>toNullable(t: T): T? { | |
return t | |
} | |
// If we pass in a `String`, we get back a `String?` | |
val s1 : String? = toNullable("" as String) | |
// So, if we pass in a `String?`, we get back a nested nullable `String??`, right? | |
// Wrong. We get a `String?` | |
val s2 : String? = toNullable("" as String?) | |
// It looks like Kotlin can't express nested nullables | |
// Why is this important? | |
// Let's have a look at `Map<K, V>` | |
// It defines the following method: get(key: K): V? | |
// Notice how it returns `V?`, where `null` is used to signal that there's no entry for a given `key` | |
val map = hashMapOf<String, Int>("key1" to 1) | |
val val1: Int? = map.get("key1") | |
val val2: Int? = map.get("key2") | |
println(val1 == null) // false | |
println(val2 == null) // true | |
// However, when we have a map with a nullable value, like `Map<String, Int?>`, the meaning of `null` is now ambiguous | |
// It can both mean that the entry doesn't exist, or that it exists but has no value | |
val map = hashMapOf<String, Int?>("key1" to 1, "key2" to null) | |
val val1: Int? = map.get("key1") | |
val val2: Int? = map.get("key2") | |
val val3: Int? = map.get("key3") | |
println(val1 == null) // false | |
println(val2 == null) // true | |
println(val3 == null) // true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Contrast this with what happens in Swift, where we can have a nested `Int??` | |
let map: [String: Int?] = ["key1": 1, "key2": nil] | |
let val1: Int?? = map["key1"] | |
let val2: Int?? = map["key2"] | |
let val3: Int?? = map["key3"] | |
print(val1 == nil) // false - entry exists | |
print(val1! == nil) // false - value exists | |
print(val2 == nil) // false - entry exists | |
print(val2! == nil) // true - value doesn't exist | |
print(val3 == nil) // true - entry doesn't exist |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment