Is there a way to set lower bounds on generic func...
# stdlib
m
Is there a way to set lower bounds on generic function params in Kotlin? Or ensure that one type param is NOT equal to another type param (or does not extend the other) at compile time? Imaginary syntax could be
Copy code
fun <A, B> myFunction(a: A, b: B) where A !: B {
   ...
}
j
I don't think there is a way to ensure type parameters are different. But what is your use case for this?
m
I’m using Java’s
Proxy.newProxyInstance()
method which requires the interface you’re proxying to be passed in. I also need to pass in a variable which implements that interface. Unfortunately at the call site, it’s easy to accidentally pass in the concrete class for both generic params as the compiler will infer it (if you don’t explicitly write them) and there will be no compile time errors. A simplified version looks like this
Copy code
inline fun <reified Concrete, reified Interface> makeProxy(concrete: Concrete) where Concrete : Interface {
   ...
   return newProxyInstance(  
       apiClass = Interface::class.java.classLoader,
       arrayOf(Interface::class.java),
       MyCustomProxyClass(concrete as Interface),
   ) as Interface
}
And the call site looks like
Copy code
fun doStuff(): MyInterface {
    makeProxy(MyConcreteClass()) // <--- In some places the compiler reads this as makeProxy<MyConcreteClass, MyConcreteClass>(MyConcreteClass())
}
j
what about making the interface class an explicit argument of
makeProxy
?
m
Yeah so you can explicitly put it in, but I want to ensure safety at the call site so other devs don’t accidentally make this mistake. It’s a large project where this method is called in 100s of spots
j
What I mean is, make the
makeProxy
function take 2 parameters:
Copy code
fun <I, I : C> makeProxy(concrete: C, target: KClass<I>): I {
   ...
   return newProxyInstance(  
       apiClass = target.java.classLoader,
       arrayOf(target.java),
       MyCustomProxyClass(concrete),
   ) as I
}
So the call site will be forced to provide both arguments, and cannot rely solely on type inference:
Copy code
fun doStuff(): MyInterface {
    makeProxy(MyConcreteClass(), MyInterface::class)
}
m
Ah yeah, I actually have that function and the
inline
version calls it. The problem is that’s not as pretty or nice to use 😂 Ideally the callsite just looks like
Copy code
MyConcreteClass().makeProxy()
(the class is actually the receiver param in my code) This requires the encapsulating function to specify
MyInterface
as the return type ofc
I’ve actually already found a workaround, but the question about type lower bounds and checking non-equal types still interests me
j
Checking non-equal types is not possible I believe. But regarding lower bounds I don't see how that would help here 🤔
m
Maybe lower bound is the incorrect terminology. It would be cool having a compile time check that either 1. A generic type param does not extend from
X
or any of its subclasses, or 2. A generic type param is an
interface
and not a
class
Applying either of those restrictions could help