Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why SomeClass::class is KClass<SomeClass> but this::class is KClass<out SomeClass>

I want to print values of properties of my class.

fun print() {
    val cl = this::class
    cl.declaredMemberProperties.filter {it.visibility != KVisibility.PRIVATE}.forEach {
        println("${it.name} = ${it.get(this)}")
    }
}

When I try to build this code I get compiler error:

Error:(34, 40) Kotlin: Out-projected type 'KProperty1<out SomeClass, Any?>' prohibits the use of 'public abstract fun get(receiver: T): R defined in kotlin.reflect.KProperty1'

When I change this to class name SomeClass everything is fine

fun print() {
    val cl = SomeClass::class
    cl.declaredMemberProperties.filter {it.visibility != KVisibility.PRIVATE}.forEach {
        println("${it.name} = ${it.get(this)}")
    }
}

So the problem is that compiler changers type of this::class to KClass<out SomeClass> instead of using KClass<SomeClass>. Any idea why does it happen?

like image 330
Goussein Minkailov Avatar asked Mar 28 '17 12:03

Goussein Minkailov


1 Answers

The reason for this difference is that, when you use the SomeClass::class reference, it is sure to be the class token representing SomeClass and not one of its possible derived classes, therefore it is KClass<SomeClass> without type projections.

But this::class written in a function of an open or abstract class or an extension function can return a class token of a derived class, therefore, to ensure type safety, the type is out-projected: KClass<out SomeClass> means that the actual type argument can be SomeClass or its subtype.

Example:

open class A {
    fun f() {
        println(this::class) // KClass<out A> because it can be KClass<B>
    }
}

class B : A()

B().f()
like image 80
hotkey Avatar answered Oct 22 '22 08:10

hotkey