I would like to have a non-generic class in kotlin that uses generics in its constructor in order to specify that a parameter. However, I can't figure out how to do this, and the Java-to-Kotlin converter for Intellij breaks.
My java class looks like this
public class Test {
interface I1 { }
interface I2 { }
private final I1 mI1;
private final I2 mI2;
public <T extends I1 & I2> Test(T host) {
mI1 = host;
mI2 = host;
}
}
The converter's output looks like this.
class Test(host: T) where T: I1, T: I2 {
internal interface I1
internal interface I2
private val mI1: I1
private val mI2: I2
init {
mI1 = host
mI2 = host
}
}
I would like to do this because in Android development it is useful to be able to specify a constructor parameter that looks like <Host extends Context & CustomCallbackInterface>
Looking at Kotlin's grammar, it seems that this is not possible at the moment. For primary constructors, the type parameters denote class type parameters:
class (used by memberDeclaration, declaration, toplevelObject) : modifiers ("class" | "interface") SimpleName typeParameters? primaryConstructor? (":" annotations delegationSpecifier{","})? typeConstraints (classBody? | enumClassBody) ;
For secondary constructors, there are no type parameters possible:
secondaryConstructor (used by memberDeclaration) : modifiers "constructor" valueParameters (":" constructorDelegationCall)? block ;
However, a constructor is just a special function. If we instead don't use the constructor, but a function of our own, we can come up with the following:
class Test {
interface I1
interface I2
private val mI1: I1
private val mI2: I2
internal constructor(host: I1, host2: I2) {
mI1 = host
mI2 = host2
}
companion object {
fun <T> create(host: T): Test where T : Test.I1, T : Test.I2 {
return Test(host, host)
}
}
}
fun <T> test(host: T): Test where T : Test.I1, T : Test.I2 {
return Test(host, host)
}
We can now call Test.create(host)
or test(host)
to create an instance.
Expanding on nhaarman's answer you can use operator overloading to make Test
's companion object implement the invoke
operator
:
class Test {
interface I1
interface I2
private val mI1: I1
private val mI2: I2
private constructor(i1: I1, i2: I2) {
mI1 = i1
mI2 = i2
}
companion object {
operator fun <T> invoke(host: T): Test where T : I1, T : I2 {
return Test(host, host)
}
}
}
You can then create a Test
object using the call syntax you want:
Test(object : Test.I1, Test.I2 {})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With