Kotlin Type Mismatch "Nothing" - kotlin

Consider the following code, which has been stripped back to illustrate only the problem with generics:
interface Node
interface GenericNode<T : GenericNode<T>> : Node {
val pointer: NodePtr<T>?
}
class NodePtr<T : Node>(private val value: T) {
fun isPointingTo(other: T): Boolean {
return value == other
}
}
class BasicNode : Node
class GenericNodeImpl(override val pointer: NodePtr<GenericNodeImpl>) : GenericNode<GenericNodeImpl>
Node may have many implementations. Here we have GenericNode<T : GenericNode<T>> which contains a pointer to another GenericNode<T : GenericNode<T>> (consider this sort of like a singly-linked list mechanism), and we have BasicNode.
Now consider the following which demonstrates the problem:
fun main(args: Array<String>) {
val a = GenericNodeImpl(null)
val b = GenericNodeImpl(NodePtr(a))
val c = GenericNodeImpl(NodePtr(b))
val d = BasicNode()
val list: List<Node> = listOf(a, b, c, d)
list.filterIsInstance<GenericNode<*>>().filter { it.pointer?.isPointingTo(a) ?: false }
}
I've declared List<Node> as it can contain any Node type, but then I want to filter any instances of type GenericNode<*>. I don't care about the specific implementation, or what T is in this case, it just has to be GenericNode<*>.
For each of those nodes, I want to know which ones are pointing to a, but isPointingTo(a) contains the following error:
Type mismatch.
Required: Nothing
Found: GenericNodeImpl
I'm assuming that the issue is caused by filtering GenericNode<*> where * is Unknown, but that is unavoidable. Is there an in or out missing somewhere?

Technically NodePtr could be contravariant in T (in T) because it only takes a T as input (to the isPointingTo() method).
As a consequence, GenericNode could also be in T, because T is only used for the pointer property which is now in T.
That being said, it doesn't solve your problem, because your problem is conceptual. You're filtering with GenericNode<*>, meaning you don't know what T is, and T could really be any subtype of GenericNode, including Nothing. This means that the following NothingGenericNode implementation could be a potential element in the list:
class NothingGenericNode(override val pointer: NodePtr<Nothing>?) : GenericNode<Nothing>
From there, you can see that pointer could be of type NodePtr<Nothing> and thus accept 0 possible values as argument of isPointingTo. The compiler protects you from that. It only allows you to pass arguments that would be valid for all possible subtypes of GenericNode. But since there is a subtype that accepts nothing at all, then your generic code cannot pass anything either.
One solution to this problem would be to be more lenient on what isPointingTo accepts. For instance it could maybe accept any subtype of Node instead of only the specific T:
fun isPointingTo(other: Node): Boolean

Related

Interfering type parameter based on another type parameter

Is it possible to Kotlin Compiler to infer type parameter based on another type parameter?
That is: infere type A based on type B in IntExample class definition.
interface Something<A>
interface Example<A, B: Something<A>>
class IntSomething: Something<Int>
// Can Int type parameter be infered by the fact that IntSomething is Something<Int>?
// If yes, how could I specify B type parameter without specifing the infered A (Int) parameter?
class IntExample: Example<Int, IntSomething> // specifing Int here is painful!!!
Imagine that we have more type parameters like that - it will be a lot of boilerplate to specify each of them if some might (theoretically) be infered.
EDIT
After an exhausive respose from #KarstenGabriel I will extend the previous example, to make it clear what for are the type parameters used here:
interface Something<A> {
val sth: A
}
interface Example<A, B: Something<A>> {
val eg: A
val something: B
}
data class IntSomething(override val sth: Int): Something<Int>
data class DescribedIntSomething(
override val sth: Int,
val description: String
): Something<Int>
data class DescribedIntExample(
override val eg: Int,
override val something: DescribedIntSomething,
): Example<Int, DescribedIntSomething> // specifing Int here is painful
fun main() {
val describedIntExample = DescribedIntExample(
eg = 1,
something = DescribedIntSomething(1, "Just one")
)
// We have to know that something is DescribedIntSomething to read description.
// Neither `*` nor `Something<Int>` is sufficient, we need `B: Something<Int>` to keep B
val description = describedIntExample.something.description
println(description)
}
So we use the type parameters - A and B as return values from eg and something
Wildcard * cannot be used as it is just means Any?. We need to keep concrete type B. (eg. to enable reading descrption in the example)
Wildcard Something<Int> cannot be used instead of B: Something<Int> for thesame reason as in the point 1
Maybe it's just an language design level. The type parameters do exists in compile time (they are ereased later), so theoretically Example<DescribedIntSomething> might be sufficient instead of Example<Int, DescribedIntSomething> as DescribedIntSomething is Something<Int>
The problem is solvable under some assumptions:
You need type parameter A only for property eg (or other similar cases).
It is okay that we convert eg to be a function instead of a property.
The desired value for eg (your A value) can be derived from the value of something (your B value). If the value is not inferred, then it is not possible to infer the type.
We then define Example without parameter A:
interface Example<B: Something<*>> {
val something: B
}
Now inside Example we do not have a possibility to obtain the type parameter of B's Something-type, because the type parameter A on Something<A> does not exist at runtime. So you cannot just ask an instance of B what its Something-type parameter is. And Kotlin cannot do that either, because the information is just not there, if it is not explicitly specified by you.
But we know the parameter at compile-time which can be used in an inline extension function with reified parameter:
inline fun <reified A, reified B : Something<A>> Example<B>.eg(): A = something.sth
(documentation: Inline functions with reified parameter and Extension functions)
In this example I assume that eg should have the value of sth.
If you want eg to be private, you can put the function inside Example and make it private, otherwise it must be specified outside of the class.
Now you can just define your subclass without the need to specify the former A parameter, but you still have the right type:
data class DescribedIntExample(
override val something: DescribedIntSomething,
) : Example<DescribedIntSomething>
fun main() {
val describedIntExample = DescribedIntExample(
something = DescribedIntSomething(1, "Just one")
)
val x = describedIntExample.eg() // x has inferred type Int and value 1
}

Access Implementation's property on variable of type Interface

I'm trying to access the delegate of the property (id) of a class (FooImpl). The problem is, this class implements an interface (Foo), and the property in question overrides a property of this interface. The delegate only exists in the class (not that it could exist in the interface).
The problem is that using the :: operator on a variable of type Foo always returns the property of Foo, not that of the actual instance. The problem in code:
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty0
import kotlin.reflect.jvm.isAccessible
interface Foo {
val id: Int
}
class FooImpl(
id: Int,
) : Foo {
override val id: Int by lazy { id }
}
val <T> KProperty<T>.hasDelegate: Boolean
get() = apply { isAccessible = true }.let { (it as KProperty0<T>).getDelegate() != null }
fun main() {
val foo: Foo = FooImpl(1)
println("foo::id.hasDelegate = ${foo::id.hasDelegate}")
println("(foo as FooImpl)::id.hasDelegate = ${(foo as FooImpl)::id.hasDelegate}")
}
This prints:
foo::id.hasDelegate = false
(foo as FooImpl)::id.hasDelegate = true
But this requires compile-time knowledge of the correct implementation. What I'm looking for is accessing the correct propert without having to specify FooImpl there.
The information is present at runtime because the least (!) intrusive workaround I have found so far is adding fun idProp(): KProperty0<*> to Foo and override fun idProp() = ::id to FooImpl and accessing the property using that.
Is there any better way than that?
I came up with this, but I don't know if there's a better way. The problem to work around is that getDelegate() has to return an actual instance of the delegate, so you need an instance of the class to be able to retrieve a delegate instance. It would really be nice if there was a hasDelegate property built in. Your version of hasDelegate will crash from the cast on unbound KProperty1's, which is all we have to work with when the specific class is unknown.
So to retrieve the delegate instance, we need to do search the class instance's member properties by name, which gives us a KProperty with covariant class type of the super-class type. Since it's covariant, we can call a consuming function like getDelegate() without casting to the invariant type. I think this logically should be safe, since we are passing an instance that we know has the matching type for the ::class that we retrieved the property with.
#Suppress("UNCHECKED_CAST")
fun <T: Any> KProperty1<T, *>.isDelegated(instance: T): Boolean =
(instance::class.memberProperties.first { it.name == name } as KProperty1<T, *>).run {
isAccessible = true
getDelegate(instance) != null
}
fun main() {
val foo: Foo = Foo2()
println("foo::id.hasDelegate = ${Foo::id.isDelegated(foo)}")
}
The problem here is that the owner of the property is resolved on compile time, not on runtime. When you do foo::id then foo (so FooImpl) become its bound receiver, but owner is still resolved to Foo. To fix this we wound need to "cast" property to another owner. Unfortunately, I didn't find a straightforward way to do this.
One solution I found is to use foo::class instead of foo::id as it resolves KClass on runtime, not on compile time. Then I came up with almost exactly the same code as #Tenfour04.
But if you don't mind using Kotlin internals that are public and not protected with any annotation, you can use much cleaner solution:
val KProperty0<*>.hasDelegate: Boolean
get() = apply { isAccessible = true }.getDelegate() != null
fun KProperty0<*>.castToRuntimeType(): KProperty0<*> {
require(this is PropertyReference0)
return PropertyReference0Impl(boundReceiver, boundReceiver::class.java, name, signature, 0)
}
fun main() {
val foo: Foo = FooImpl(1)
println(foo::id.castToRuntimeType().hasDelegate) // true
}
We basically create a new instance of KProperty, copying all its data, but changing the owner to the same type as its bound receiver. As a result, we "cast" it to the runtime type. This is much simpler and it is also cleaner because we separated property casting and checking for a delegate.
Unfortunately, I think Kotlin reflection API is still missing a lot of features. There should be hasDelegate() function, so we don't have to provide receivers, which is not really needed to check if property is delegated. It should be possible to cast KProperty to another type. It should be possible to create bound properties with some API call. But first of all, it should be possible to do something like: Foo::id(foo), so create KProperty of the runtime type of foo. And so on.

Kotlin type is not inferred into generic function

I have a generic function to fetch/get any list out of the SharedPreferences. However, when I wanted to test, that it does not work, when I saved a list of say, Messages and ask for a list of say, Ints, it still worked. It just ignored the type I precised and returned a List of JsonObjects. When I debugged the whole code, I found, that apparently the function does not care about the inferred class type. I´ll first put here the code, so I can explain the problem:
fun <T> getListFromPreferences(preferences : SharedPreferences, key : String)
: MutableList<T> {
val listAsString = preferences.getString(key, "")
val type: Type = object : TypeToken<List<T>>() {}.type
val gson = SMSApi.gson
return gson.fromJson<ArrayList<T>>(listAsString, type)
?: ArrayList()
}
So, what I would expect, was, that when I call the function like this:
PreferenceHelper.getListFromPreferences<Message>(preferences, TEST_KEY)
the "type" variable in the above code should return List. However the result the debugger shows me is: java.util.List<? extends T>
I have absolute no idea, why the inferring does not work, but I´d really like it to work to ensure, what I am requesting is actually what I get, for obvious reasions.
Does anybody know a reason and a solution for this weird behaviour?
Due to type erasure, actual type information about T is lost, so basically this method returns List<Any?> (even if you pass Int as T).
To preserve the actual type, you need to declare this method with reified parameter:
inline fun <reified T> getListFromPreferences(preferences : SharedPreferences, key : String)
: MutableList<T> {
//...
}

Use-site vs declaration-site difference in type projections in Kotlin

Type Hierarchy
open class Fruit()
open class CitrusFruit : Fruit()
class Orange : CitrusFruit()
Declaration-site Variance
The Crate is used as a producer or consumer of Fruits.
Invariant class
class Crate<T>(private val elements: MutableList<T>) {
fun add(t: T) = elements.add(t) // Consumer allowed
fun last(): T = elements.last() // Producer allowed
}
Covariant classout
class Crate<out T>(private val elements: MutableList<T>) {
fun add(t: T) = elements.add(t) // Consumer not allowed: Error
fun last(): T = elements.last() // Producer allowed
}
Contravariant classin
class Crate<in T>(private val elements: MutableList<T>) {
fun add(t: T) = elements.add(t) // Consumer allowed
fun last(): T = elements.last() // Producer not allowed: Error
}
Use-site Variance
All these use-site projections are for the invariant class Crate<T> defined above.
No Projection
No subtyping allowed: Only the Crate<Fruit> can be assigned to a Crate<Fruit>.
fun main() {
val invariantCrate: Crate<Fruit> = Crate<Fruit>(mutableListOf(Fruit(), Orange()))
invariantCrate.add(Orange()) // Consumer allowed
invariantCrate.last() // Producer allowed
}
Covariant Projectionout
Subtyping allowed: Crate<CitrusFruit> can be assigned to Crate<Fruit> when CitrusFruit is a subtype of Fruit.
fun main() {
val covariantCrate: Crate<out Fruit> = Crate<CitrusFruit>(mutableListOf(Orange()))
covariantCrate.add(Orange()) // Consumer not allowed: Error
covariantCrate.last() // Producer allowed
}
Contravariant Projectionin
Subtyping allowed: Crate<CitrusFruit> can be assigned to Crate<Orange> when the CitrusFruit is a supertype of Orange.
fun main() {
val contravariantCrate: Crate<in Orange> = Crate<CitrusFruit>(mutableListOf(Orange()))
contravariantCrate.add(Orange()) // Consumer allowed
contravariantCrate.last() // Producer allowed: No Error?
}
Questions
Is my understanding and the use of type projection correct in the given example?
For contravariance: why is the last()(producer) function not allowed at declaration-site but allowed at use-site? Shouldn't the compiler show an error like it shows in the declaration-site example? Maybe I'm missing something? If the producer is allowed for contravariance only at use-site, what could be the use case for it?
I prefer detailed answers with examples but any kind input will be much appreciated.
Let's start with the use-site.
When you write
val contravariantCrate: Crate<in Orange> = ...
the right side could be a Crate<Orange>, Crate<Fruit>, Crate<Any?>, etc. So the basic rule is that any use of contravariantCrate should work if it had any of these types.
In particular, for all of them
contravariantCrate.last()
is legal (with type Orange, Fruit, and Any? respectively). So it's legal for Crate<in Orange> and has type Any?.
Similarly for covariantCrate; calling the consumer method technically is allowed, just not with Orange. The problem is that a Crate<Nothing> is a Crate<out Fruit>, and you couldn't do
val covariantCrate: Crate<Nothing> = ...
covariantCrate.add(Orange())
Instead the parameter type is the greatest common subtype of Fruit, CitrusFruit, Nothing, etc. which is Nothing. And
covariantCrate.add(TODO())
is indeed legal because the return type of TODO() is Nothing (but will give warnings about unreachable code).
Declaration-site in or out effectively say that all uses are in/out. So for a contravariant class Crate<in T>, all calls to last() return Any?. So you should just declare it with that type.
My guess is that the difference between declaration-site and use-site contravariance is that delcaration-site can be statically checked by the compiler, but when using projections there is always the original, unprojected object in existence at run-time. Therefore, it is not possible to prevent the creation of the producer methods for in projections.
When you write:
class Crate<in T>(private val elements: MutableList<T>) {
fun add(t: T) = elements.add(t) // Consumer allowed
fun last(): T = elements.last() // Producer not allowed: Error
}
The compiler can know at compile-time that no method on Crate<T> should exist that produces a T, so the definition of fun last(): T is invalid.
But when you write:
val contravariantCrate: Crate<in Orange> = Crate<CitrusFruit>(mutableListOf(Orange()))
What has actually been created is a Crate<Any?>, because generics are erased by the compiler. Although you specified that you don't care about producing an item, the generic-erased Crate object still exists with the fun last(): Any? method.
One would expect the projected method to be fun last(): Nothing, in order to give you a compiler-time error if you try to call it. Perhaps that is not possible because of the need for the object to exist, and therefore be able to return something from the last() method.

What is the purpose of having bound class reference return a covariant type?

I'm playing with reflection and I came out with this problem. When using bound class reference via the ::class syntax, I get a covariant KClass type:
fun <T> foo(entry: T) {
with(entry::class) {
this // is instance of KClass<out T>
}
}
As I could learn from the docs, this will return the exact type of the object, in case it is instance of a subtype of T, hence the variance modifier.
However this prevents retrieving properties declared in the T class and getting their value (which is what I'm trying to do)
fun <T> foo(entry: T) {
with(entry::class) {
for (prop in memberProperties) {
val v = prop.get(entry) //compile error: I can't consume T
}
}
}
I found that a solution is using javaClass.kotlin extension function on the object reference, to get instead the invariant type:
fun <T> foo(entry: T) {
with(entry.javaClass.kotlin) {
this // is instance of KClass<T>
}
}
This way, I get both the exact type at runtime and the possibility to consume the type.
Interestingly, if I use a supertype instead of a generic, with the latter method I still get access to the correct type, without the need of variance:
class Derived: Base()
fun foo(entry: Base) {
with(entry.javaClass.kotlin) {
println(this == Derived::class)
}
}
fun main(args: Array<String>) {
val derived = Derived()
foo(derived) // prints 'true'
}
If I got it correct, ::class is equal to calling the java getClass, which returns a variant type with a wildcard, while javaClass is a getClass with a cast to the specific type.
Still, I don't get why would I ever need a covariant KClass, when it limits me to only produce the type, given that there are other ways to access the exact class at runtime and use it freely, and I wonder if the more immediate ::class should return an invariant type by design.
The reason for covariance in bound ::class references is, the actual runtime type of an object the expression is evaluated to might differ from the declared or inferred type of the expression.
Example:
open class Base
class Derived : Base()
fun someBase(): Base = Derived()
val kClass = someBase()::class
The expression someBase() is typed as Base, but at runtime it's a Derived object that it gets evaluated to.
Typing someBase()::class as invariant KClass<Base> is simply incorrect, in fact, the actuall result of evaluating this expression is KClass<Derived>.
To solve this possible inconsistency (that would lead to broken type-safety), all bound class references are covariant: someBase()::class is KClass<out Base>, meaning that at runtime someBase() might be a subtype of Base, and therefore this might be a class token of a subtype of Base.
This is, of course, not the case with unbound class references: when you take Base::class, you know for sure that it's the class token of Base and not of some of its subtypes, so it's invariant KClass<Base>.