In this section, we will learn what the safe call operator is and how to use it in Kotlin.
Note: we’re assuming you’re already familiar with the Kotlin null and nullable type.
What is Safe Call Operator in Kotlin?
The safe call operator is used to check the value of a nullable variable before invoking one of its members (properties or functions).
Now, if the target variable’s value was null, then the safe call operator will terminate the operation (stops a call for a member name) and returns the value null immediately. But then, if the target variable had an actual value (non-null) then the safe call operator will allow the call to proceed and the target member will be invoked.
This is useful because, if we call a member’s name on a null value, we will get an exception (error) and our program may crash! But now using the safe call operator, we will make sure first the variable has a value and then we call the target member! So no error will occur here.
How to use safe call operator in Kotlin? Syntax:
This is the syntax of using the safe call operator:
variable?.memberName
Here, the variable is the nullable one that we want to check and see if it has a null value or not. So we put a question mark after the name of the variable and then call for a member of the object that the variable is pointing at (if it is actually pointing to an object).
So here the value of the variable was null, then the call to the member will be ignored and simply a value null will return. Otherwise, if there was an object this variable pointing at, then the safe call operator allows the operation to proceed.
Note: you can only call this operator on a nullable variable and not a non-null type of variable.
Example: using safe call in Kotlin
fun main(){ var name:String? = null var res = name?.uppercase() println("The uppercase version of name is: $res") name = "john" res = name?.uppercase() println("The uppercase version of the name is: $res") }
Output:
The uppercase version of name is: null The uppercase version of the name is: JOHN
Here the value of the name
variable is of type nullable String. This means the value might end up being null! So we need to use the safe call operator to first check and see if this variable is null and then proceed to call one of its members (uppercase () function in this example).
Now for the first time we’ve called the value of the name variable, we can see that the value of the variable is null and so the safe call operator terminated the operation and stopped the call to the uppercase()
function. That’s why we got the value null as a result.
But for the second call to the name variable, it has an actual string value and so the safe call operator allowed the operation to proceed and the uppercase() function is invoked then.
Chaining Safe Calls in Kotlin
Chaining safe calls is the process of calling this operator multiple times in one statement.
For example, if there’s an object with an inner object (like an Employee object with an Address object in this object) if the property of the object that is holding the inner object is of nullable type then there’s a chance that the value for that inner object might be a null (like the Employee object’s value for the Address object is set to null). So now by chaining of safe calls we can ensure that if we called the property of the object and it was null, our program won’t crash and it simply returns the value null instead.
Alright, now let’s run an example to see how this chaining of safe calls works in Kotlin.
Example: chain of safe calls in Kotlin
class Address{ var city:String = "LA" var state:String = "CA" } class Employee{ var address:Address? = null var firstName:String = "John" var lastName:String = "Doe" } fun main(){ var address = Address() var emp:Employee? = Employee() emp?.address = address println(emp?.address?.city) println(emp?.address?.state) }
Output:
LA CA
How does chaining safe calls work in Kotlin?
Here the emp
variable is of type nullable Employee. Also, the address property inside the Employee class is of type nullable Address.
This means if we want to call the emp variable, we need to use the safe call operator. But also if we want to call the address property of this object in order to access one of the properties of that inner object, then we also need to run the safe call operator here as well.
This is what happened in these two statements:
println(emp?.address?.city) println(emp?.address?.state)
Here we chained the safe call operator and this is what will happen behind the scene:
– First, our program checks to see if the emp variable is pointing to a null value or an actual object.
– Because the variable is pointing to a real object, then our program allows the operation to proceed.
– Now there’s a call to the address
property which is a nullable type. So our program again checks to see if this property has the value null or is pointing to an actual object.
– Now because the address property also has a real object, then again our program allows the operation to proceeds and so we can get the values for the city and state properties.
Note: if for any of these calls to the safe call operator the target variable or property was pointing to a null value, the entire operation would be terminated and the value null would’ve been returned.
Note: again, the job of the safe call operator is to simply return a null value when it sees a call to a variable that is pointing to a null value. This way, the safe call operator stops a program from accidentally crashing.
Kotlin Safe Calls and Assigning Values
We also use the safe call operator to assign a value to a property of a nullable object.
If we consider the last example, the address property is of nullable type and so if we want to assign a value to one of its property, we first need to check and see if the address
property has the value null or actually pointing to an object.
So the safe call is required when an assignment is going to happen.
Example: using the safe call operator to assign a value
class Address{ var city:String = "LA" var state:String = "CA" } class Employee{ var address:Address? = null var firstName:String = "John" var lastName:String = "Doe" } fun main(){ var address = Address() var emp:Employee? = Employee() emp?.address = address emp?.address?.city = "NY" emp?.address?.state = "NY" println(emp?.address?.city) println(emp?.address?.state) }
Output:
NY NY