I'm having an issue with Kotlin generics and gener...
# announcements
m
I'm having an issue with Kotlin generics and generic java classes. I'm trying to write a function for a DI lib that will takes two Class instances, one of interface and one of class implementing the interface (akin to Dagger's
@Binds
). So far, I can make it work with Kotlin types and even Java ones but it fails for generic Java types (like List<*> and ArrayList<*>). Is this limitation of generics system or am I doing something wrong? function:
fun <C : I, I: Any> bind(clazz: Class<C>, iface: Class<I>)
usage:
Copy code
bind(ArrayList::class.java, List::class.java) //kotlin types, works fine
bind(java.util.ArrayList::class.java, java.util.List::class.java) // error: inferred type ArrayList<*> is not a subtype of List<*>
m
What error do you get?
m
added it to "usage" part
Full error
Copy code
Type parameter bound for C in fun <C : I, I : Any> bind(clazz: Class<C>, iface: Class<I>): Unit
 is not satisfied: inferred type ArrayList<*> is not a subtype of List<*>
m
Right. My guess is that it’s because the type parameter on the Java types are invariant.
While the Kotlin ones are covariant.
m
Any idea for a workaround?
Interestingly enough, calling the function from java works fine 😄
m
So the workaround is to use Kotlin types in Kotlin and Java types in Java? 😛
m
looks so 😄
m
Just overload the function:
Copy code
inline fun <C : I, I: Any> bind(clazz: KClass<C>, iface: KClass<I>) = bind(clazz.java, iface.java)
If you need to do this often, you may want to publish an extra artifact with those overloaded functions.
m
That gives the same error unfortunately
Copy code
Type parameter bound for C in inline fun <C : I, I : Any> bind2(clazz: KClass<C>, iface: KClass<I>): Unit
 is not satisfied: inferred type ArrayList<*> is not a subtype of List<*>
Called like this
bind2(java.util.ArrayList::class, java.util.List::class)
t
For a similar problem the following solution was suggested to me: Instead of having one function, split it into two parts like so:
Copy code
fun <I: Any> bind(iface: Class<I>) = BindOp(iface)
class BindOp<T>(val t: T)
infix fun <I:Any, C:I> BindOp<I>.to(clazz: Class<C>): Unit = TODO()