Smart cast does not cast String? to String after !value.isNullOrBlank()

Viewed 255

I want to add to the list objects only if they have all fields, and try this code:

data class Response(val id: String, val name: String)
val list = mutableListOf<Response>()

val id : String? = "test_id"
val name : String? = "test_name"

if (!id.isNullOrBlank() and !name.isNullOrBlank()) {
    list.add(Response(id, name)) // Type mismatch. Required String, Found String?
}

But I got an error: Type mismatch. Required String, Found String? What is the correct (and compact) way to do it?

2 Answers

As a recommendation: always try to use && instead of bitwise and to evaluate your conditions. Seldomly is there any reason to use a bitwise and (there are some use-cases, but in most cases you just want to have a short-circuiting evaluation of your conditions, even more so if there is some complex calculation/service calls within one of the functions).

From what I see and expect the smart cast should work, even more so because && already does work. I didn't find any appropriate or matching issue, so you may want to open a new ticket for this.

Note also that the smart cast should work due to the Kotlin contract defined in isNullOrBlank which basically checks whether the value underneath is null so it might be related to the evaluation of the contracts, and/or the inlining of the function and/or something of the former combined with the bitwise and.

An alternative approach I usually like to do, without involving smart casts:

val id : String = getId()?.takeIf { it.isNotBlank() } ?: return
val name : String = getName()?.takeIf { it.isNotBlank() } ?: return
list.add(Response(id, name))

Here you verify the value while you get it and abort if you cannot use it.

Related