SIRS
SIRS

Reputation: 624

Cast types to their respective not nullable types

I have an extension function something like this:

inline fun <A, B, C> Pair<A, B>.notNull(code: (A, B) -> C) {
    if (this.first != null && this.second != null) {
        code(this.first, this.second)
    }
}

with that, I can do something like this:

Pair(username, password).notNull { user, pass -> 
    // code to execute when username and password is not null
}

The problem is, user and password type is still in nullable form, so I still need to use ?. to call user and pass, even though user and pass is not null

How to cast it to their respective not nullable type?

Maybe something like this, but for generic:

inline fun <C> Pair<Editable?, Editable?>.notNull(code: (Editable, Editable) -> C) {
    if (this.first != null && this.second != null) {
        code(this.first!!, this.second!!)
    }
}

Upvotes: 0

Views: 403

Answers (3)

Naetmul
Naetmul

Reputation: 15552

I think this will work.

inline fun <A: Any, B: Any, C> Pair<A?, B?>.notNull(code: (A, B) -> C) {
    if (this.first != null && this.second != null) {
        code(this.first!!, this.second!!)
    }
}

Here, the types A and B are not defined to be subtypes of Any?. They are restricted to subtypes of Any, so they are not null. (Of course, every subtype of Any is a subtype of Any?.)

However, the type of this will be Pair<A?, B?>, so it will be a pair of nullables. All not-null types are subtypes of their corresponding nullable types, so any Pair can call this extension function.


EDIT: For an archive, yole's answer seems more preferred (not using !!): https://stackoverflow.com/a/48960855/869330

Upvotes: 1

yole
yole

Reputation: 97133

In this case the smart cast does not work because you're accessing properties of a class declared in another module. It will work if you store the property values in local variables:

inline fun <A : Any, B : Any, C> Pair<A?, B?>.notNull(code: (A, B) -> C) {
    val first = this.first
    val second = this.second
    if (first != null && second != null) {
        code(first, second)
    }
}

Upvotes: 2

General Answer :

if you declare a generic class or function they can include nullable while substituting their type params :

Example :

class Help<T>{
 fun printHelp(message :T){
     message?.render();
 }
}

so in this case message is nullable despite T isn't marked with T? So to avoid passing a nullable parameter type and guarantee that a non-null type will always be substituted you can change it to :

class Help<T : Any>{
 fun printHelp(message :T){
     message.render();
 }
}

Upvotes: 2

Related Questions