Swift Optional and Kotlin Nullable— A comparison

Elye
Elye
Mar 5 · 8 min read

Handling the million dollar mistake, null reference is a must in modern programming languages. Both Swift and Kotlin has taken similar yet subtly different approach.

Perhaps sharing both together would give one who has view on one to see the other side would be a good comparison.

By default all variables CANNOT be NULL

In Java, if ever a new class object is instantiate, it could either be null or having some value. i.e.

Integer number = null; // Valid
String letter = null; // Valid

Not so for Kotlin and Swift

The below are invalid for Swift and Kotlin

// Swift
let number: Int = nil; // Invalid
let letter: String = nil; // Invalid
// Kotlin
val number: Int = null; // Invalid
val letter: String = null; // Invalid

Both introduce a new type to store NULL

Optional in Swift

In Swift, the new type is called Optional. The way to declare it is as below

let number: Int? = nil
let letter: String? = nil
print(number) // print `nil`
print(letter) // print `nil`

If you assign a value to it

let number: Int? = 10
let letter: String? = "abc"
print(number) // print `Optional(10)`
print(letter) // print `Optional("abc")`

So in another word, it is just a wrapper type (or imagine a box) on the original type (looks similar to Optional<T> of Java, but declared in a more elegant way using ?).

If want to represent Optional it in a diagram, it would look like below

So you could actually do the below

let number: Int??? = 10
let letter: String??? = "abc"
print(number) // print `Optional(Optional(Optional(10)))`
print(letter) // print `Optional(Optional(Optional("abc")))`

Nullable in Kotlin

In Kotlin, the new type is called Nullable. The way to declare it is as below (looks almost the same as Swift, except for the nil isn’t it?)

val number: Int? = null
val letter: String? = null
print(number) // print `null`
print(letter) // print `null`

However, if we assign value to it, it will looks as below, behave similar to the non-null version of it.

val number: Int? = 10
val letter: String? = "abc"
print(number) // print `10`
print(letter) // print `abc`

How could it be so? This is because the non-null version of the Type is treated as a subclass of the nullable version of the Type

When one declare Int??? or String???, it is although possible to have such declaration, the compiler will complaint Redundant ‘?’.

It doesn’t make sense to have nullable-nullable-…, given nullable-nullable… is really just nullable. And it’s value still print as a value of it’s non-nullable form shown below.

val number: Int??? = 10 // Warning Redundant ‘?’
vak letter: String??? = "abc" // Warning Redundant ‘?’
print(number) // print `10`
print(letter) // print `abc`

Accessing nullable object’s function

? — Swift Optional Chaining, Kotlin Safe Call

The “?” character is needed before the nullable object’s function could be accessed. Without it, it will produce compilation error, so the potential Null Pointer Exception (NPE) could be prevented.

When “?” is used, when the object is not null, then only it’s function will be executed. Else a null will be return instead.

// Swift Optional Chaining
let string: String? = "ABC"
let nothing: String? = nil
print(string.lowercased()) // Compile error
print(string?.lowercased()) // print `Optional("abc")`
print(nothing?.lowercased()) // print `nil`

// Kotlin Safe call
val string: String? = "ABC"
val nothing: String? = null
print(string.toLowerCase()) // Compile error
print(string?.toLowerCase()) // print `abc`
print(nothing?.toLowerCase()) // print `null`

Non-null to nullable type assignment: Legal

Swift : Wrapping into Optional

It is allowed to assign a non-null to Optional variable of the same type in Swift. It is like wrapping the variable into Optional type

let actualNumber: Int = 10
let actualLetter: String = "abc"
print(actualNumber) // print `10`
print(actualLetter) // print `abc`
let number: Int? = actualNumber
let letter: String? = actualLetter
print(number) // print `Optional(10)`
print(letter) // print `Optional("abc")`

Kotlin : Casting into Nullable

It is allowed to assign a non-null to nullable variable of the same type in Kotlin. It is like casting the variable to it’s parent nullable type, which is legal.

val actualNumber: Int = 10
val actualLetter: String = "abc"
print(actualNumber) // result in `10`
print(actualLetter) // result in `abc`
val number: Int? = actualNumber
val letter: String? = actualLetter
print(number) // result in `10`
print(letter) // result in `abc`

Nullable to non-null type assignment: Error

In both languages, such assignment is not permitted

// Swift
let number: Int? = 1
let letter: String? = "1"
let actualNumber: Int = number // Compile error
let actualLetter: String = letter // Compile error
// Kotlin
val number: Int? = 10
val letter: String? = "abc"
val actualNumber: Int = number // Compile error
val actualLetter: String = letter // Compile error

This is where the protection of accidental causing Null Pointer Exception (NPE) from happening, where one can’t accidentally assign a null value to a non-null variable.

Force assign nullable to non-null type

Swift: Unconditional unwrapping

To force an Optional turning into it’s original, one could unwrap it using as!

let number: Int? = 10
let actualNumber: Int = number as! Int

But a shorter way would be as below

let number: Int? = 10
let actualNumber: Int = number!

But these are unsafe, as it will crash in case number == nil.

Kotlin: Force casting, double bang!

To force an casting to a non null value, one could unwrap it using as

val number: Int? = 10
val actualNumber: Int = number as Int

But a shorter way would be as below

let number: Int? = 10
let actualNumber: Int = number!!

But these are unsafe, as it will crash in case number == null.

Graceful assign nullable to non-null type

To make it safe one could do as below

// Swift
let number: Int? = 10
if number != nil {
let actualNumber: Int = number!
}
// Kotlin
val number: Int? = 10
if (number != null) {
let actualNumber: Int = number!!
}

However, these looks so yesterday… so Java… so primitive, having to explicitly compare to null.

Let’s look at more elegant way of doing it for both languages.

Swift: Optional Binding

With Optional Binding, no more explicit checking for nil. Note the actualNumber is only scope within the parenthesis.

let letter: String? = "ABC"
if let actualLetter = letter {
print(actualLetter.lowercased())
}

In Swift, there is also a guard that could to handle it gracefully, where it would terminate if the nil is found, or continue. In this case the actualNumber is set beyond the guard scope.

let letter: String? = "ABC"
guard let actualLetter = letter else { return }
print(actualLetter.toLowerCase())

Kotlin: Standard function

In Kotlin, there’s no special syntax introduced to handle that. But there’s a provided generic functions (which is named standard functions) that came in real handy.

The one that was normally used is let as below, but one could use other like apply, run etc.

val letter: String? = 10
letter?.let {
print(it.toLowerCase())
}

The above example is, the it is actually the non nullable of letter that could be used within the scope.

To reads more about Kotlin Function, refer

Graceful handling of null value

In Java world, we do something like below at times.

int messageLength = -1; // -1 to indicate not setif (message != null) {
messageLength = message.length;
} else {
messageLength = 0;
}

Swift: Nil coalescing

In Swift, this is made so much nicer with the ?? (Nil coalescing) operator

let messageLength = message?.count ?? 0

Kotlin: Elvis expression

In Kotlin, this is made so much nicer with the ?: (Elvis expression) operator

val messageLength = message?.length ?: 0

Safe casting : as?

Both Swift and Kotlin allow one attempt to cast one type to another. If casting successful, it will result a nullable type (optional for Swift) of the cast result

// Swift
let number: Int = 10
let x = number as? Int // x = Optional(10), x is Int?
let x = number as? String // x = nil, x is String?
// Kotlin
val number: Int = 10
val x = number as? Int // x = 10, x is Int?
val x = number as? String // x = null, x is String?

“After I know it is not null” handling

Sometimes after we are so sure the Optional or Nullable object is not null, it is such a hassle to continue using ? on that object. How does the languages handle such scenario?

Swift: Implicit Unwrapping

Other than having Optional type, Swift provide another type that indicate Implicit Unwrapping type i.e. the Type ends with !

let letter: String? = "ABC"
let unwrapLetter: String! = letter
print(letter) // print `Optional("ABC")`
print(letter?.lowercased()) // print `Optional("abc")`
print(unwrapLetter) // print `Optional("ABC")`
print(unwrapLetter.lowercased()) // print `abc`; no "?" needed

The unwrapLetter above is an implicit unwrapped type. It is actually a optional type, but could be used without the ? type as shown in print(unwrapLetter.lowercased()). Also notice the result is abc instead of Optional("abc").

This type has make need of having ? unnecessary.

Nonetheless, this type has it’s risk, as it doesn’t guarantee nil will not be there, and will crash when it does.

Kotlin: Smart casting

Unlike Swift, Kotlin doesn’t have another type that does that. But it has a feature call smart casting that comes handy in this case.

Smart casting is a feature is upon knowing that an object is a specific subclass type, it will be automatically cast to that type without the coder have to explicit cast it.

val actualLetter: String? = "ABC"
if (actualLetter == null) return
print(actualLetter.toLowerCase()) // no `?` needed

Te above is a very simplified case, where if actualLetter is null, the function will terminate. This means after that line, we’ll know that actualLetter is confirm not null.

With this, actualLetter is now smartly cast to String, and could call toLowerCase() without need the safe call ? operator.

Smart casting is only performed if the variable is confirmed not changeable between the check and the usage. Hence it is safe.


Elye

Written by

Elye

Learning and Sharing Android and iOS Development

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade