kotlin - What is the purpose of having bound class reference return a covariant type? -
i'm playing reflection , came out problem. when using bound class reference via ::class
syntax, covariant kclass type:
fun <t> foo(entry: t) { with(entry::class) { // instance of kclass<out t> } }
as learn docs, return exact type of object, in case instance of subtype of t
, hence variance modifier. prevents retrieving properties declared in t
class , getting value (which i'm trying do)
fun <t> foo(entry: t) { with(entry::class) { (prop in memberproperties) { val v = prop.get(entry) //compile error: can't consume t } } }
i found solution using javaclass.kotlin
extension function on object reference, instead invariant type:
fun <t> foo(entry: t) { with(entry.javaclass.kotlin) { // instance of kclass<t> } }
this way, both exact type @ runtime , possibility consume type.
interestingly, if use supertype instead of generic, latter method still access correct type, without 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 got correct, ::class
equal calling java getclass
, returns variant type wildcard, while javaclass
getclass
cast specific type. still, don't why ever need covariant kclass, when limits me produce type, given there other ways access exact class @ runtime , use freely, , wonder if more immediate ::class
should return invariant type design.
the reason covariance in bound ::class
references is, actual runtime type of object expression evaluated might differ declared or inferred type of expression.
example:
open class base class derived : base() fun somebase(): base = derived() val kclass = somebase()::class
the expression somebase()
typed base
, @ runtime it's derived
object gets evaluated to.
typing somebase()::class
invariant kclass<base>
incorrect, in fact, actuall result of evaluating expression kclass<derived>
.
to solve possible inconsistency (that lead broken type-safety), bound class references covariant: somebase()::class
kclass<out base>
, meaning @ runtime somebase()
might subtype of base
, , therefore might class token of subtype of base
.
this is, of course, not case unbound class references: when take base::class
, know sure it's class token of base
, not of of subtypes, it's invariant kclass<base>
.
Comments
Post a Comment