In Kotlin, class parameter names are visible to the user of the class.
I want to define onClick
as a parameter, but the class already has a function named onClick
, and I cannot reference the parameter.
How do I reference a class parameter whose name conflicts with a method name?
So far the best thing I could do was copying the parameter to a field. I am not sure if it is worth doing: it moves the ugliness inside a class, but that class is in the same project, to be maintained by the same people.
open class A() { // Already exists, I cannot change it
open fun onClick() {
println("A.onClick()")
}
}
class B(onClick: () -> Unit = { println("param onClick()") }) : A() {
var x = 2
private val uglyOnClick = onClick // workaround: one more field for the same value (ugh!)
override fun onClick() {
println("B.onClick() $x")
if (x-- > 0) { // prevent endless recursion in case recursion happens (ideally, it should not)
super.onClick()
//this@B.onClick() // recursion, but I need to reference the class parameter
//this.onClick() // recursion, but I need to reference the class parameter
//onClick() // recursion, but I need to reference the class parameter
/* any of the above three print:
B.onClick() 2
A.onClick()
B.onClick() 1
A.onClick()
B.onClick() 0
*/
//getOnClick() // Unresolved reference: getOnClick
uglyOnClick() // this one works as expected, but it's an ugly workaround
/* the one above prints, as expected:
B.onClick() 2
A.onClick()
param onClick()
*/
}
}
}
What is required:
class B(onClick: () -> Unit = { println("param onClick()") }) : A() {
override fun onClick() {
println("B.onClick()")
super.onClick()
:::MAGIC:::.onClick()
}
}
}
/* it must print:
B.onClick()
A.onClick()
param onClick()
*/
The onClick
parameter you're passing to B
is a constructor parameter, and you can only access it inside B
's constructor code and property initializers. It won't be available later, which is why you can't access it inside the onClick()
function.
To fix it:
val
keyword to the constructor parameter, turning it into a property that will be stored with the object.invoke()
to make sure you're referencing the property, not the function.class B(val onClick: () -> Unit = { println("param onClick()") }) : A() {
override fun onClick() {
onClick.invoke()
}
}