Using a KMutableProperty1
to access a classes property works both as a getter and setter.
class BaseClass(
var baseInt: Int = 0,
var baseInnerClass: InnerClass = InnerClass()
)
class InnerClass(
var innerInt: Int = 0,
)
val target = BaseClass()
val kMutableProperty1b = (BaseClass::baseInt)
kMutableProperty1b.set(target, 4)
val baseInt = kMutableProperty1b.get(target)
To be able to access nested properties like
BaseClass::innerClass -> InnerClass:innerInt
I tried to up chain two kMutableProperty1
with
fun <A, B, C> ((A) -> B).chained(getter : (B) -> C) : (A) -> C = { getter(this(it)) }
With that, the inner properties can be read, but not set:
val chainedKMutableProperty = baseMutableProperty.chained(InnerClass::innerInt)
val innerInt = chainedKMutableProperty(target)
chainedKMutableProperty.set(target, 5) // Not available
In Swift something similar can be achieved using KeyPaths
let target = BaseClass()
let aKeyPath = \BaseClass.baseInt
target[keyPath: aKeyPath] = 4
let baseInt = target[keyPath: aKeyPath]
let bKeyPath = \BaseClass.baseInnerClass
let chainedKeyPath = bKeyPath.appending(path: \InnerClass.innerInt)
let innerInt = target[keyPath: chainedKeyPath]
target[keyPath: chainedKeyPath] = 5
How can I do the same in Kotlin - chaining property accessors and maintaining both the ability to read and write?
I don't think there is something like this already in Kotlin or Java stdlib. We can easily create it by ourselves, although I don’t think it is a good idea to stick to
KProperty
. This interface isn’t just a generic accessor interface. It is a very specific thing: a property of a class. And we don't deal with class properties here.Instead, I suggest to create our own interfaces. Below is a simple POC: