Programming in Kotlin: Fundamentals

Aug 9 2022 · Kotlin 1.6, Android 12, IntelliJ IDEA CE 2022.1.3

Part 3: Functions & Nullability

20. Create & Consume Nullables

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 19. Introduction Next episode: 21. Challenge: Use Nullables

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Transcript: 20. Create & Consume Nullables

So far, all the constants and variables you’ve used and created had values. However, in programming, that isn’t always the case.

This is why in most programming languages a concept exists, which describes values which, well, don’t really have a value. This concept is called Null.

Null, or no value, is often used to describe a value which may or may not be there. For example, I usually carry my keys around with me at all times.

But I also tend to lose them in my backpack, or jacket, and I just can’t seem to find them anywhere.

In that case they are null to me.

In development, it’s common to face a situation where you might not know if a value is there or not. Another good example is working with files. If you try to open a filePath which doesn’t exist, you will get a null file.

Now, developers are humans, and they sometimes make mistakes in code, unfortunately ending up with null values.

Null is often referred to as the billion dollar mistake. This is because it’s estimated that null values, and errors in programs, have resulted in billions of dollars of repairs, patches and software changes.

However, in Kotlin you can avoid losing soooo much money, by using a built in system called the Nullable Type.

Nullable types are types which allow you to use null to represent a constant or a variable. If a value is not marked with a Nullable Type, it cannot be null, you get a compile time error if you try to assign null to it. This makes sure you don’t do any funny business with non-nullable values!

To create nullable types and values, there is a pretty simple convention and syntax. All you have to do is add a ? (question mark) at the end of the type to tell the program that this value may not exist, and you can assign null to it.

Then, whenever you want to use a nullable value, you have to apply specific type of calls and checks, otherwise, you get more compile time errors, which stops you from breaking your program accidentally.

Let’s see how to save a couple billion dollars using Nullable types in Kotlin :]

// Starter code
val myName = "Emmanuel"
val nickname: String

When I was in high school, we had about 3 student bearing the same name as mine: Emmanuel.

For this reason, each Emmanuel had their own nickname so that we could tell who is who. My nickname at that time was “Stretchy”, which was because I was the tallest in the class.

But over the years I’ve gained new nicknames, and have lost that high school one, and quite frankly I don’t have one right now. You could say that my nickname is currently null because i have none. :]

Let’s change this constant to represent that. First you have to let the compiler know that it’s a nullable value by explicitly assigning it a nullable String type like so:

val myName = "Emmanuel"
val nickname: String?

I added a question mark notation at the end of the type. You can now assign it the value of null, and print it out:

val myName = "Emmanuel"
val nickname: String? = null

println(nickname)

Run the project, and you’ll see null is printed out.

Let’s see what happens if you try to assign a null value to a non-nullable type. Add another constant to the properties, name it lastName and assign null to it:

val myName = "Emmanuel"
val nickname: String? = null
val lastName: String = null

You can see IDE complains and if you run the project, you will get a compile time error that you cannot assign null to a non-nullable value! This is to keep you from accidentally breaking your code and possibly losing billions of dollars.

Once you change the type to be a nullable String? it will work:

val myName = "Emmanuel"
val nickname: String? = null
val lastName: String? = null

But how can you use the values now, or access their properties like the String’s length. Let’s try getting the length of the nickname:

val nicknameLength = nickname.length

This just doesn’t work. The error might be a bit hard to see, but if you hover over the dot operator (.), you’ll see that the compiler is not happy about it, and that it gives you different options to fix the issue.

I’ll click on the dot operator then click the red bulb icon. You can see we have a menu with two options. Select “Add non-null asserted call”

Two exclamation marks are added before the dot and this forces the value, guaranteeing to the compiler that it is not null.

val nicknameLength = nickname!!.length

This is the one thing you should try to avoid when dealing with nullables, the non-null asserted operator. It forces the value to be non-null, but if it is null, you program will crash. You use this when you’re very sure that the variable or constant would have a value.

To show you what i mean, print out this constant:

println(nicknameLength)

Run the program now, and you should see an exception in the run panel. An exception is primarily an event which signals that something went wrong during program execution. You’ll learn about exceptions as you progress in you Kotlin development journey.

Now, a better way to deal with this case is to use the safe-call operator. This was the other option that appeared in the fix menu when you clicked the reb bulb icon few moments ago. You use a safe call by adding a question mark before the dot like so:

val nicknameLength = nickname?.length
println(nicknameLength)

The safe call operator will execute and return the right hand side of the operator, if the value is not null. If it’s null, it will return null instead. This means that if you call the length with a safe call like we have here, you essentially get back a nullable Int?, since the value can be the length, which is an Int, or null, if the nickname is null.

Run the program now, and it won’t crash, it will print out null instead.

The safe call operator is really good even if you have multiple calls chained, as you can also chain the operators like so:

val nicknameLength = nickname?.length?.toDouble()
println(nicknameLength)

Here you can see a chained call toDouble(). If any of the safe call operators fail due to a null value, the entire expression will be null. If not, they will get executed as if there were no null values included, and you’ll transform the value to what you need.

Change the nickname to be “Stretchy”:

val nickname: String? = "Stretchy"

Then run the program once more to see that you get a Double type value of the nickname’s length.

Now, sometimes you want to check if a value is not null and then work with a non-null version of a nullable value if the check succeeds. That’s a lot of nulls in just one sentence. This is called a null-check.

Let me show you what i mean. Enter the following code:

if (lastName != null) {
  println("My last name is ${lastName.length} characters long!")
} else {
  println("I don't have a last name!")
}

You open an if statement, and then within it, check if the value is different from null. You can then proceed to work with that value, within the scope of the if block.

Now, remember, lastName is a nullable String? but notice how, when you hover over the lastName inside the body of the if statement, the editor says it has been smart cast to String.

This is another cool mechanism Kotlin has, where if you check for nullability on values that won’t change like constants, and they are not null, the compiler will know it can change the type of the value to be a non-nullable type.

This is called casting to a type, or smart casting to non-nullable type. Then, you can freely use it in the rest of the scope as a non-nullable type. In this case the scope of the if statement.

With this, you dont need to put a question mark before the . operator when accessing the length of the string because Kotlin has smart casted it.

Run the program now, and because you didn’t put in the lastName, you should see the else block printed out.

Using checks and safe call operators are closely tied, as you can use a safe call operator to verify some data using an if, and then smart cast it in the rest of the if block, like so:

if (nickname?.isEmpty()) {
  println("You don't have a nickname! It's length is: ${nickname.length}")
}

This code looks correct but it seems we have an error in the code. Hover over it. It says that the if statement required a Boolean but a nullable Boolean? was found. And this is simply because nickname is a nullable string which means that it might have no value. So the isEmpty() method returns a nullable Boolean?. To solve this, click on the bulb icon and select “Add == true.” With this, the expression will always result in a boolean value.

Now within the print statement, the nickname is smart casted to a non-nullable string.

There are other ways you can ensure your values are not null without using an if.

You can use the Elvis operator. Enter the following code to see it in action:

val myNickname = nickname ?: myName
println(myNickname)

It is called Elvis, because when you tilt your head, it kind of looks like Elvis Presley’s hair! :]

What it does is pretty simple, it returns the left hand side, if the value is not null, and the right hand side, if it is null.

This means that, for my current nickname, it will return "Stretchy", but if I were to change it to null, it would return myName instead

Run the project. And you can see it returns “Stretchy”.

Now change the nickname to null, and run it again!

val myName = "Emmanuel"
val nickname: String? = null
val lastName: String? = null

It returns “Emmanuel” instead of null this time around.