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>>
}
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 withAnyno matter the variance or supertype:is given as
kotlin.Any. In this case,*meansAny?, but I see you don't support nullability on purpose, so that's fine.However, for
it returns
kotlin.Anytoo. I'd expect there to be a way to know that*meansNumberhere.Finally,
also gives
kotlin.Any, which, according to the docs should bekotlin.Nothing. This is because the variance of typeTisininComparable<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:
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: