I love this Swift syntax; it's very helpful for many things:
var foo: Bar = Bar() { willSet { baz.prepareToDoTheThing() } didSet { baz.doTheThing() } }
and I'd love to do this in Kotlin. However, I can't find the proper syntax!
Is there anything in Kotlin like this?
var foo: Bar = Bar() willSet() { baz.prepareToDoTheThing() } didSet() { baz.doTheThing() }
didSet is called right after the data is stored and it has a default constant oldValue which shows the previous value that is overwritten. willSet and didSet cannot be used at computed property since set function has already covered their functionalities and getter only stored property cannot be set actually!
Property Observers in Swift. In Swift, you can attach property observers to variables to run code when the variable changes. These property observers are called willSet and didSet. The former runs right before the property changes, and the latter runs right after the changes were made.
Property Observers. Property observers observe and respond to changes in a property's value. Property observers are called every time a property's value is set, even if the new value is the same as the property's current value.
Although Kotlin doesn't provide a built-in Swift-style solution for property changes observation, you can still do it in several ways depending on what your goal is.
There is observable(...)
delegate (in stdlib) that allows you to handle the property changes. Usage example:
var foo: String by Delegates.observable("bar") { property, old, new -> println("$property has changed from $old to $new") }
Here, "bar"
is the initial value for property foo
, and the lambda is called each time after the property is assigned, allowing you to observe the changes.There's also vetoable(...)
delegate that allows you to prevent the change.
You can use custom setter for a property to execute arbitrary code before/after actual value change:
var foo: String = "foo" set(value: String) { baz.prepareToDoTheThing() field = value baz.doTheThing() }
As @KirillRakhman noted, this solution is quite efficient since it introduces no overhead in method calls and objects, though the code will be a little duplicated in case of several properties.
In general, you can implement your own property delegate, explicitly providing the property behavior in getValue(...)
and setValue(...)
functions.
To simplify your task, use ObservableProperty<T>
abstract class that allows you to implement delegates that observe property changes (like observable
and vetoable
above) Example:
var foo: String by object : ObservableProperty<String>("bar") { override fun beforeChange(property: KProperty<*>, oldValue: String, newValue: String): Boolean { baz.prepareToDoTheThing() return true // return false if you don't want the change } override fun afterChange(property: KProperty<*>, oldValue: String, newValue: String) { baz.doTheThing() } }
For your convenience, you can write a function that creates the delegate object:
fun <T> observing(initialValue: T, willSet: () -> Unit = { }, didSet: () -> Unit = { } ) = object : ObservableProperty<T>(initialValue) { override fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = true.apply { willSet() } override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = didSet() }
Then you just pass lambdas to it as willSet
and didSet
(the default argument for them is { }
). Usage:
var foo: String by observing("bar", willSet = { baz.prepareToDoTheThing() }, didSet = { baz.doTheThing() }) var baq: String by observing("bar", didSet = { println(baq) })
In any case, it's up to you to make sure that the code observing the changes doesn't set the property again as it will likely fall into infinite recursion, or else you might check it in the observing code whether the setter is called recursively.
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