-
Notifications
You must be signed in to change notification settings - Fork 0
Description
First of all, great job :) A multiplatform reflection library is a great addition to the ecosystem :)
We're looking at migrating a library to multiplatform in the future, but we rely heavily on reflection and type logic, so I'm curious to see how far Kaverit can help us.
I do have a couple suggestions and concerns.
Variance and * notations:
I noticed TypeToken.getGenericParameters() fills in * parameters of generics with Any no matter the variance or supertype:
generic<List<*>>().getGenericParameters()[0]is given as kotlin.Any. In this case, * means Any?, but I see you don't support nullability on purpose, so that's fine.
However, for
interface Test<T : Number>
generic<Test<*>>().getGenericParameters()[0]it returns kotlin.Any too. I'd expect there to be a way to know that * means Number here.
Finally,
generic<Comparable<*>>().getGenericParameters()[0]also gives kotlin.Any, which, according to the docs should be kotlin.Nothing. This is because the variance of type T is in in Comparable<in T>.
Combining types
Aside from that, I'd also be interested in a way to "add" multiple types together and do some logic, finding the lowest common parent between two types.
Something like:
fun sharedTypes(a: TypeToken<*>, b: TypeToken<*>): List<TypeToken<*>> {
val aTypes = listOf(a) + a.getSuper()
val bTypes = listOf(b) + b.getSuper()
return (aTypes intersect bTypes).toList() + TypeToken.Any
}
fun lowestCommonType(a: TypeToken<*>, b: TypeToken<*>): TypeToken<*> =
sharedTypes(a, b).first()
lowestCommonType(generic<Int>(), generic<Double>()) == generic<Number>()but a bit more efficient maybe, and it should be able to calculate lowestCommonType(generic<List<Int>>(), generic<List<Double>>()) correctly. This might also require some variance/bound checks on generics. Specifically, I'd be interested in calculating the combinations of types such as the highlighting of the IDE can do like this:
interface A : Comparable<Double>
interface B : Comparable<Int>
interface C : Comparable<Number>
interface D : List<Double>
interface E : List<Number>
fun function(a: A, b: B, c: C, d: D, e: E) {
val list1 = listOf(a, c) // inferred as List<Comparable<Double>>
val list2 = listOf(a, b) // inferred as List<Comparable<Nothing>>
val list3 = listOf(d, e) // inferred as List<List<Number>>
}