kotlinandroid-jetpack-compose

Disambiguate name conflict and reference class parameter


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()
*/

Solution

  • 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:

    1. Add the val keyword to the constructor parameter, turning it into a property that will be stored with the object.
    2. Use 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()
      }
    }