I am writing a class implementing an interface that exposes a setSelected
method. This class will have a selected
property:
private class Foo : IFoo {
var selected = false
override fun setSelected(isActive: Boolean) {
selected = isActive
}
}
However the compiler complains, as Kotlin generates a setter for selected
, that the two methods clash:
Error:(14, 9) Kotlin: [com.bar.jvmTest] Platform declaration clash: The following declarations have the same JVM signature (setSelected(Z)V):
fun <set-selected>(<set-?>: Boolean): Unit defined in foo.bar.baz.Foo
fun setSelected(isActive: Boolean): Unit defined in foo.bar.baz.Foo
Error:(24, 9) Kotlin: [com.bar.jvmTest] Platform declaration clash: The following declarations have the same JVM signature (setSelected(Z)V):
fun <set-selected>(<set-?>: Boolean): Unit defined in foo.bar.baz.Foo
fun setSelected(isActive: Boolean): Unit defined in foo.bar.baz.Foo
override
and so my class does not fully implement the interface:
Error:(11, 13) Kotlin: [com.bar.jvmTest] Class 'Foo' is not abstract and does not implement abstract member public abstract fun setSelected(isActive: Boolean): Unit defined in bar.baz
selected
to e.g. dataSelected
so that the generated setter doesn't clash with the method, but there should be a way to keep this simple property name and implement the interface as expected.
override
?You can create a property without a backing field, and then override your abstract function like this:
class Foo : IFoo {
private var hiddenSelected = false
val selected get() = hiddenSelected
override fun setSelected(isActive: Boolean) {
hiddenSelected = isActive
}
}
Update:
After sleeping on it, I think this solution is not so good at all because of 2 reasons:
hiddenSelected
) which is not necessary=
operator)I think the best solution would be this:
class Foo : IFoo {
@set:JvmName("setSelected0")
var selected: Boolean = false
set(value) { setSelected(value) }
override fun setSelected(isActive: Boolean) {
// Possibly some other stuff
println("Now i'm using my own setter!")
selected = isActive
}
}
Using the annotation @JvmName you can tell the compiler how to name that specific function. Kotlin automatically creates a getter and setter for every property, so you need to use the set:
modifier to annotate the setter of that property and not the property itself.
Also it is very important that you implement a custom setter for that property so you can safely write this:
Foo().selected = true // This also prints "Now i'm using my own setter!"
instead of this:
Foo().setSelected(true)
Your setter can possibly do some other stuff (like printing that log), which can have side effects, so you need to make sure that you call the right setter. This can be sometimes a bit tricky since Kotlin always creates a setter for every mutable variable (var
).