I have two constructors which are different only in their lambda return type. Is there any option how to overload them? I was trying to use JvmOverloads annotation, but it didn't work.
constructor(db : Database, handler: ( transaction: Transaction) -> Unit) : this(db, Handler<Transaction>( {handler.invoke(it)}))
@JvmOverloads
constructor(db : Database, handler: ( transaction: Transaction) -> Any) : this(db, Handler<Transaction>( {handler.invoke(it)}))
You cannot define constructors with signatures that differ only in generic parameters (in your case, it's generic parameters for Function1<in P1, out R>
) because the signatures would clash after generics erasure.
However, in your case Unit
is subtype of Any
, and since Function<in P1, out R>
is covariant on R
, you can pass a function that returns Unit
to the second constructor, so just remove the first one.
Simplified example:
class C(val action: (Int) -> Any)
fun main(args: Array<String>) {
val f: (Int) -> Unit = { println(it) }
C(f)
}
For more complicated cases, consider changing to factory functions: unlike constructors, you can annotate them with @JvmName
to avoid the signatures clash:
@JvmName("createCUnit")
fun createC(f: (Int) -> Unit) = C(f)
fun createC(f: (Int) -> Any) = C(f)
When targeting JVM backend, all Kotlin classes are compiled to JVM bytecode. The problem with java's bytecode is type erasure. This means that all info about generics is removed (it's Java's issue not Kotlin's).
Declaring functional type (transaction: Transaction) -> Unit
is eqivalent to using this type: Function1<Transaction, Unit>
. However, for JVM bytecode both Function1<Transaction, Unit>
and Function1<Transaction, Any>
are the same.
This means that both your constructors have the same signature in JVM world.
You can "simulate" constructors using companion object
class MyClass {
constructor(db: Database, h: Handler<Transaction>)
companion object {
operator fun invoke(db: Database, handler: (transaction: Transaction) -> Unit) = MyClass(db, Handler<Transaction>({ handler.invoke(it) }))
@JvmName("alternative_constructor")
operator fun invoke(db: Database, handler: (transaction: Transaction) -> Any) = MyClass(db, Handler<Transaction>({ handler.invoke(it) }))
}
}
And usage looks like this:
fun main(args: Array<String>) {
val db = Database()
MyClass(db, Handler { }) //real constructor
MyClass(db){ } //version from companion object
}
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