What do `Delegates.observable` and `Delegates.vetoable` provide, and how do they differ?
answer
- observable = afterChange, react only
- vetoable = beforeChange, return false to reject
- both on var, both via Delegates
- built on ObservableProperty
- vetoed write is silent (no exception)
basics
~10 sBoth let you run code whenever a property changes. observable notifies you after a change happened; vetoable lets you inspect the new value first and reject it so the property keeps its old value.
solid answer
~40 s`Delegates.observable(initial) { property, old, new -> ... }` is a stdlib property delegate that fires a callback **after** each assignment, giving you the `KProperty`, old value, and new value — useful for logging, UI invalidation, or triggering side effects. `Delegates.vetoable(initial) { property, old, new -> Boolean }` fires a callback **before** the assignment commits: if your handler returns `false`, the assignment is rejected and the property retains its old value; `true` lets it through. Both are built on `ObservableProperty<T>`, which exposes overridable `beforeChange` and `afterChange` hooks; `observable` overrides `afterChange`, `vetoable` overrides `beforeChange`. They apply to `var` properties via `by`. This is another example of delegated properties generalizing behavior: instead of writing custom getters/setters with backing fields, you compose a stdlib delegate.
code
kotlin · 4 linesvar age: Int by Delegates.vetoable(0) { _, old, new ->
new >= 0 // negative ages rejected; age keeps old value
}
age = -5 // ignored; age stays at old valuego deeper
Knows observable lets you run code when a property changes.
Distinguishes observable (after) from vetoable (before, can reject) and writes basic usage.
Explains the ObservableProperty base with beforeChange/afterChange and the silent-veto gotcha.
Reasons about property-write interception as a design pattern, trade-offs of silent veto vs throwing, and when a custom ObservableProperty subclass is warranted.
## The two delegates Both live in `kotlin.properties.Delegates` and are used with `by` on a **`var`**. ### `observable` ```kotlin var name: String by Delegates.observable("<unset>") { prop, old, new -> println("${prop.name}: $old -> $new") } ``` - Signature: `observable(initialValue, onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit)`. - The handler runs **after** the new value is stored (an `afterChange` hook). - You cannot cancel the change — it has already happened. Use it for reacting: logging, marking state dirty, notifying listeners. ### `vetoable` ```kotlin var percent: Int by Delegates.vetoable(0) { _, _, new -> new in 0..100 // accept only valid values } ``` - Signature: `vetoable(initialValue, onChange: (property, oldValue, newValue) -> Boolean)`. - The handler runs **before** the value is committed (a `beforeChange` hook). Returning `false` **vetoes** the assignment: the property keeps its old value. Returning `true` allows it. - Use it for validation/invariants guarded right at the property. ## Shared machinery: `ObservableProperty` Both are implemented on top of the abstract class `ObservableProperty<T>`, which has: - `protected open fun beforeChange(property, oldValue, newValue): Boolean` — return `false` to reject (default returns `true`). - `protected open fun afterChange(property, oldValue, newValue): Unit` — react after. `vetoable` overrides `beforeChange`; `observable` overrides `afterChange`. You could subclass `ObservableProperty` directly to do both. ## Key differences | | observable | vetoable | |---|---|---| | Hook | afterChange | beforeChange | | Can cancel? | No | Yes (return false) | | Handler return | Unit | Boolean | | Typical use | logging, side effects | validation, invariants | ## Gotchas - Both work on `var`; not on `val` (a `val` cannot change). - The callback also is **not** called when the value is read, only on assignment. - A vetoed assignment is silent — no exception; the caller may not realize the write was ignored, so combine with validation feedback if needed. ## Why it fits the stdlib model Like `lazy`, these show Kotlin mapping a behavior ('observe/intercept property writes') onto a **delegate object** rather than language syntax, keeping property declarations declarative.
- Does a vetoed assignment throw?No. The assignment is silently ignored and the old value is kept; you must surface feedback yourself if needed.
- How would you get both before- and after-change behavior?Subclass ObservableProperty<T> and override both beforeChange and afterChange.
saying these in an interview costs you the question
- Saying observable can cancel a change
- Thinking vetoable throws on rejection
- Claiming these work on val
- Mixing up which hook (before vs after) each uses
- Believing the callback fires on reads too