0Pricing
Kotlin Academy · Lesson

observable and vetoable Delegates

React to property changes with observable and conditionally reject with vetoable.

observable and vetoable Delegates is a free Kotlin Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Kotlin Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Property Delegates Refresher

Kotlin property delegates let a separate object handle getValue and setValue. Delegates.observable and Delegates.vetoable are built-in delegates from the standard library.

import kotlin.properties.Delegates
var name: String by Delegates.observable("initial") { prop, old, new ->
    println("${prop.name}: $old -> $new")
}
fun main() { name = "Alice"; name = "Bob" }

observable Syntax

observable takes an initial value and a callback invoked after each change with the property, old value, and new value.

import kotlin.properties.Delegates
var score: Int by Delegates.observable(0) { _, old, new ->
    println("Score changed from $old to $new")
}
fun main() {
    score = 10
    score = 25
    score = 0
}

Triggering UI Updates

Observable delegates are great for triggering UI refresh when a backing property changes, without a full LiveData setup.

import kotlin.properties.Delegates
class ViewModel {
    var title: String by Delegates.observable("Loading") { _, _, new ->
        println("Render: $new") // pretend this updates UI
    }
}
fun main() {
    val vm = ViewModel()
    vm.title = "Home"
    vm.title = "Settings"
}

vetoable Syntax

vetoable invokes a callback before assignment. If the callback returns false, the new value is rejected and the old value is kept.

import kotlin.properties.Delegates
var age: Int by Delegates.vetoable(0) { _, old, new ->
    new >= 0 // reject negative ages
}
fun main() {
    age = 25; println(age)  // 25
    age = -1; println(age)  // 25 (rejected)
    age = 30; println(age)  // 30
}

Combining Validation with vetoable

Use vetoable to enforce domain invariants at the property level without external validation logic.

import kotlin.properties.Delegates
var email: String by Delegates.vetoable("") { _, _, new ->
    new.contains("@")
}
fun main() {
    email = "user@example.com"; println(email) // set
    email = "invalid";          println(email) // still previous
}

Logging Changes with observable

Use observable for audit logging: record every state transition automatically without touching business logic.

import kotlin.properties.Delegates
val log = mutableListOf<String>()
var status: String by Delegates.observable("IDLE") { _, old, new ->
    log.add("$old -> $new")
}
fun main() {
    status = "RUNNING"
    status = "DONE"
    println(log)
}

observable in a Class

Both delegates work inside class bodies just like any other property.

import kotlin.properties.Delegates
class Counter {
    var count: Int by Delegates.observable(0) { _, old, new ->
        if (new > old) println("Incremented to $new")
        else println("Decremented to $new")
    }
}
fun main() {
    val c = Counter()
    c.count = 5
    c.count = 3
}

vetoable for Range Constraint

Constrain a numeric property to a valid range using vetoable.

import kotlin.properties.Delegates
var volume: Int by Delegates.vetoable(50) { _, _, new ->
    new in 0..100
}
fun main() {
    volume = 80;  println(volume) // 80
    volume = 150; println(volume) // 80 (rejected)
    volume = 0;   println(volume) // 0
}

Chaining Delegates

You can combine observable logic manually by writing a custom delegate that calls observable under the hood, adding extra logic at each step.

import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class LoggedDelegate<T>(initial: T) : ReadWriteProperty<Any?, T> {
    private var value: T = initial
    override fun getValue(t: Any?, p: KProperty<*>) = value
    override fun setValue(t: Any?, p: KProperty<*>, v: T) {
        println("Setting ${p.name} = $v"); value = v
    }
}
var x: Int by LoggedDelegate(0)
fun main() { x = 10; x = 20 }

Thread Safety Note

Neither observable nor vetoable is thread-safe by default. For concurrent access, protect mutations with a Mutex or synchronize externally.

import kotlin.properties.Delegates
// Not thread-safe as-is:
var sharedState: String by Delegates.observable("start") { _, old, new ->
    println("$old -> $new")
}
// In coroutines, wrap access with Mutex if needed

Practical Pattern: Form Validation

Use vetoable per field for declarative form validation: each field self-validates on assignment.

import kotlin.properties.Delegates
data class Form(
    var username: String = "",
    var password: String = ""
) {
    var validUsername: String by Delegates.vetoable("") { _,_,v -> v.length >= 3 }
    var validPassword: String by Delegates.vetoable("") { _,_,v -> v.length >= 8 }
}
fun main() {
    val f = Form()
    f.validUsername = "ab";       println(f.validUsername) // ""
    f.validUsername = "alice";    println(f.validUsername) // "alice"
    f.validPassword = "short";    println(f.validPassword) // ""
    f.validPassword = "secure123";println(f.validPassword) // "secure123"
}

Quick Check

When does vetoable invoke its callback?

Recap

observable notifies after each change; vetoable runs before assignment and can reject the new value. Both are great for logging, validation, and reactive property patterns without external libraries.

Frequently asked questions

Is the “observable and vetoable Delegates” lesson free?

Yes — the full text of “observable and vetoable Delegates” is free to read here on the web, and the Kotlin Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Kotlin Academy course, upgrade to CoddyKit PRO.

What will I learn in “observable and vetoable Delegates”?

React to property changes with observable and conditionally reject with vetoable. You practise Kotlin Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Kotlin Academy?

No prior experience is required. Kotlin Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “observable and vetoable Delegates” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Kotlin Academy lesson?

Yes. Every Kotlin Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. by lazy: Deferred Initialization Deep Dive
  2. observable and vetoable Delegates
  3. Writing a Custom ReadWriteProperty Delegate
  4. Delegates for Preferences, Map-Backed Properties & Logging
← Back to Kotlin Academy