Exploring practical aspects of null checking in Kotlin

Javid Museyibli
4 min readJan 1, 2021
Exploring practical aspects of null checking in Kotlin

There are various ways of null checking in Kotlin. Let’s say we have a Student data class which is composed like following:

data class Student(
val firstName: String,
val lastName: String,
val middleName: String? = null
var lastSubmission: Submission? = null
)
data class Submission(
val timeStamp: Long
)

Looking at the class we can understand that any instance of Student will always have a first name and a last name, while having a middle name is optional and may have a null value. Let say we need to need to write a function which will return the full name of the student. If the student’s first name is John, last name is Smith and the middle name is Doe, it will return John Doe Smith, and if the student does not have a middle name it will return just John Smith. Thus, a member function getFullName() can be written as below:

fun getFullName(): String {
if (middleName != null) {
return "$firstName $middleName $lastName"
} else {
return "$firstName $lastName"
}
}

This code will run without any problems and return the expected output, however this is not the most Kotlinish syntax to use. This code below can be replaced with below using an combination of a ?.let block and an elvis operator:

fun getFullName(): String {
return middleName?.let {
"$firstName $it $lastName"
} ?: "$firstName $lastName"
}

Let’s analyze the code in detail. This is a more concise way to achieve what we wanted, and perhaps more human-readable. It follows exactly the same logic as above implementation. middleName?.let{} block only runs if a student has a middle name, and evaluates to whatever value returned from the block. If the middleName is null, ?.let the block will not run and elvis operator will return the value expression next to that evaluates to.

?.let method also allows chaining. For example, the following code will place uppercased value of the middle name into the full name if it exists and if not will skip both of let blocks.

fun getFullName(): String {
return middleName?.let {
it.toUpperCase()
}?.let {
"$firstName $it $lastName"
} ?: "$firstName $lastName"
}

What is interesting here is that in the this case a new variable is created that stores the unwrapped value of the nullable type inside each let block since middleName is immutable property. This means when we call the getFullName() function in a loop or in a recursive function two extra new variables will be introduced on each iteration. Does this mean that we should avoid using let statements completely? The answer is no.

Using ?.let on a mutable variable we create an immutable copy of the variable called it which is it is scoped to the block. See example below:

fun getLastSubmissionDate(): String {
return lastSubmission?.let {
val dateFormat = SimpleDateFormat("dd/MM/yy hh:mm a")
val netDate = Date(it?.timeStamp)
dateFormat.format(netDate)
} ?: "This student has no submission"
}

This guarantees that when the value of the property is open for change from many sources, you refer a consistent instance. To see this in detail let’s look at a function first implemented using if checks and the ?.let block. Assume, we have gradeLastSubmission which accepts the student instance as an argument and is scheduled to grade the last submission of the student at specified deadline sharply.

fun gradeLastSubmission(student: Student): Int {
return if (student.lastSubmission != null) {
// #1: Check for system updates (apx. 2 mins)
// #2: Load plagarism-checker software (apx. 1 mins)
// #3: Student uploads a new version of assignment
// #4: Instantiate grader
// #5: Check if submission is late, grade with 0.
// #6: Check if assignment meet other requirements
// #7: Grade
grader.grade(it)
} else 0
}

In this example, because the student uploaded a new version of the assignment on step #3, when the code will react step #5 it will grade the submission with 0.

fun gradeLastSubmission(student: Student): Int {
return student.lastSubmission?.let {
// #0: Check if submission is late, grade with 0.
// #1: Check for system updates (apx. 2 mins)
// #2: Load plagarism-checker software (apx. 1 mins)
// #3: Student uploads a new version of assignment
// #4: Instantiate grader
// #5: Check if submission is late, grade with 0.
// #6: Check if assignment meet other requirements
// #7: Grade
grader.grade(it)
} ?: 0
}

However in this case, even if a student updates the submission, once the grading started, the new submission will be ignored as ?.let block will work on the immutable non-nullable value of Submission.

In this article we have tried to explore ?.let blocks in Kotlin and see how null checking can be achieved by using them. We have also discussed when ?.let block might be useful and when expensive. If you liked this article make sure to follow my channel to keep more articles like this coming and clap as much as you want! :)

Don’t forget to 👏🏻. Clap as much as you want!

--

--

Javid Museyibli

Young enthusiastic software developer, currently full-time at PASHA Bank building Android and iOS applications.