Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin data classes and nullable types

I'm new to Kotlin and I don't know why compiler complains about this code:

data class Test(var data : String = "data")

fun test(){
  var test: Test? = Test("")
  var size = test?.data.length
}

Compiler complains with test?.data.length, it says that I should do: test?.data?.length. But data variable is String, not String?, so I don't understand why I have to put the ? when I want to check the length.

like image 807
Victor Manuel Pineda Murcia Avatar asked Feb 03 '17 13:02

Victor Manuel Pineda Murcia


People also ask

What are nullable types in Kotlin?

Nullable and Non-Nullable Types in Kotlin – Kotlin type system has distinguish two types of references that can hold null (nullable references) and those that can not (non-null references). A variable of type String can not hold null. If we try to assign null to the variable, it gives compiler error.

What are data classes in Kotlin?

Data classes specialize in holding data. The Kotlin compiler automatically generates the following functionality for them: A correct, complete, and readable toString() method. Value equality-based equals() and hashCode() methods.

Is any nullable Kotlin?

Since Kotlin variables are non-nullable by default, you may encounter a few problems if you are used to programming with Java. This is why we learned the main difference between Java's and Kotlin's default behaviors.

What does nullable mean in Kotlin?

Kotlin Android. In Kotlin, the type system distinguishes between references that can hold null (nullable references) and those that can not (non-null references). For example, a normal property can't hold a null value and will show a compile error.


2 Answers

The expression test?.data.length is equivalent to (test?.data).length, and the test?.data part is nullable: it is either test.data or null. Therefore it is not null-safe to get its length, but instead you should use the safe call operator again: test?.data?.length.

The nullability is propagated through the whole calls chain: you have to write these chains as a?.b?.c?.d?.e (which is, again, equivalent to (((a?.b)?.c)?.d)?.e), because, if one of the left parts is null, the rest of the calls cannot be performed as if the value is not-null.

like image 193
hotkey Avatar answered Oct 09 '22 07:10

hotkey


If you don't want to use safe call before each non-nullable component of the call chain, you can get the result of the first safe call into a new variable with the standard extension functions run or let:

// `this` is non-nullable `Test` inside lambda 
val size = test?.run { data.length }   

// or: `it` is non-nullable `Test` inside lambda
val size = test?.let { it.data.length }

Note that size is still nullable Int? here.

like image 20
Ilya Avatar answered Oct 09 '22 07:10

Ilya