Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is intersection casting possible in Kotlin?

I have a method in Java like so:

public <T extends A & B> methodName(T arg, ...)

where A is a class and B is an interface.

In my kotlin class, I have another variable of type C, and I wish to achieve the following:

if (variable is A && variable is B) {
    methodName(variable, ...)
} else {
    // do something else
}

Is it possible to properly cast variable so that it may be used as an argument without errors?

Currently, the variable has a setter method, so smart casting isn't available. However, I have also tested it with a local val and the value is inferred to have type Any which doesn't help.

like image 730
Allan W Avatar asked Jun 09 '17 03:06

Allan W


People also ask

What is smart casting in Kotlin?

Smart cast is a feature in which the Kotlin compiler tracks conditions inside of an expression. If the compiler finds a variable that is not null of type nullable then the compiler will allow to access the variable.

What is type casting in Kotlin?

Kotlin Android. Type check is a way of checking the type( DataType ) or Class of a particular instance or variable while runtime to separate the flow for different objects. In few languages, it's also denoted as Run Time Type Identification (RTTI) .

Is instance of in Kotlin?

Unlike Java, we don't have an "instance of" operator in Kotlin. However, we have an "is" operator in Kotlin for type checking and casting.

How do you check the object type in Kotlin?

Basically, the is operator is used to check the type of the object in Kotlin, and “!is” is the negation of the “is” operator. Kotlin compiler tracks immutable values and safely casts them wherever needed. This is how smart casts work; “is” is a safe cast operator, whereas an unsafe cast operator is the as operator.


1 Answers

Kotlin does not support intersection types. This causes variable to be smart cast to Any, because that is the common ancestor of A and B.

However, Kotlin does support generic type constraints. You can use this to constrain a type parameter to one or more types. This can be used on both methods and classes. This is the syntax for functions (the equivalent of your methodName in Kotlin):

fun <T> methodName(arg: T)
    where T : A,
          T : B {
    ....
}

You can use this to get around your problem by creating a class which extends both A and B, and then delegates the implementation of these types to your object. Like this:

class AandB<T>(val t: T) : A by t, B by t
    where T : A,
          T : B

You can now call methodName by changing your if-test to check if it is a AandB<*>:

if (variable is AandB<*>) {
    methodName(variable, ...)
}

You do need to wrap variable in a AandB somewhere though. I don't think you can do it if you don't have the type information for variable available anywhere.

Note: The AandB class does not implement hashCode, equals or toString. You could implement them to delegate to t's implementation.

Note 2: This only works if A and B are interfaces. You can not delegate to a class.

like image 62
marstran Avatar answered Sep 27 '22 17:09

marstran