I am having class of type A, which has contructor, that requires parameter x and has some optional parameters:
class A(x: String, y: String = "default_y")
Now I want to reference constructor with required parameters:
var function: (String) -> A = ::A
Now I am getting problem of incompatible types as signature of that constructor is 2 strings, not just one.
When I add this constructor overload, compiler stops complaining:
class A(x: String, y: String = "default_y") {
constructor(x: String): this(x, "default_y")
}
//added just so you can see full code
var function: (String) -> A = ::A
I am getting this bit of redundancy now. I can of course do something about it (extract "default_y" to constant or remove default parameter from primary constructor) to remove redundancy, but it is all just sugar code that doesn't really do anything. Just allows me to reference it without complaining.
Is there way to reference constructor (and probably function as well) as functions with only required parameters?
As stated here and also here, you cannot make use of default arguments via reflection.
The default value of a method parameter is an arbitrary expression which can only be represented as a chunk of bytecode; there is no other representation that can be used in reflection. Parameter Info retrieves default parameter values by parsing source code.
As a workaround, you could let the compiler generate the JVM overloads for your constructor and then use Java reflection to invoke the constructor that takes the single String argument:
class A @JvmOverloads constructor(x: String, val y: String = "default_y")
val con: Constructor<A> = A::class.java.constructors
.filterIsInstance<Constructor<A>>()
.find { it.parameterCount == 1 } ?: throw IllegalStateException("Not found!")
val newInstance: A = con.newInstance("myArg")
println(newInstance.y) // Prints 'default_y'
EDIT:
With callBy you can also invoke the constructor using Kotlin reflection:
val con = MyClass::class.constructors.first()
val newInst =
con.callBy(mapOf(con.parameters.first() to "myArg"))
While there's no way to get a function reference with the default parameters removed from the signature, you can use a lambda instead of a function reference and call the constructor providing only the required argument:
val function: (String) -> A = { A(it) } // uses the default for `y`
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