Delegates for Preferences, Map-Backed Properties & Logging
Apply delegates to SharedPreferences, Map storage, and audit logging.
Delegates for Preferences, Map-Backed Properties & Logging is a free Kotlin Academy lesson on CoddyKit — lesson 4 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.
Map-Backed Properties
Kotlin allows delegating properties to a Map directly. Reading the property looks up its name in the map.
class User(map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
fun main() {
val u = User(mapOf("name" to "Alice", "age" to 30))
println(u.name) // Alice
println(u.age) // 30
}MutableMap Delegate
For mutable properties, delegate to a MutableMap and mutations update the underlying map.
class Settings(private val map: MutableMap<String, Any?> = mutableMapOf()) {
var theme: String by map
var fontSize: Int by map
}
fun main() {
val s = Settings()
s.theme = "dark"
s.fontSize = 16
println(s.theme) // dark
println(s.fontSize) // 16
}JSON Deserialization with Map Delegate
Parse a JSON-like map and expose its fields as typed properties using map delegation — great for dynamic data.
class ApiResponse(data: Map<String, Any?>) {
val id: Int by data
val title: String by data
val published: Boolean by data
}
fun main() {
val response = ApiResponse(mapOf("id" to 1, "title" to "Kotlin Rocks", "published" to true))
println(response.title) // Kotlin Rocks
println(response.published) // true
}Logging Delegate Pattern
Wrap any delegate with logging to trace every read and write transparently across all delegated properties.
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class Logged<T>(private var v: T) : ReadWriteProperty<Any?, T> {
override fun getValue(t: Any?, p: KProperty<*>): T {
println("[READ] ${p.name} = $v"); return v
}
override fun setValue(t: Any?, p: KProperty<*>, value: T) {
println("[WRITE] ${p.name}: $v -> $value"); v = value
}
}
var config: String by Logged("default")
fun main() { println(config); config = "production" }Combining Map + Logging
Layer a logging wrapper around map delegation for full auditability of dynamic property access.
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class TrackedMap(private val map: MutableMap<String,Any?> = mutableMapOf()) {
inner class Delegate<T> : ReadWriteProperty<Any?,T> {
@Suppress("UNCHECKED_CAST")
override fun getValue(t:Any?,p:KProperty<*>): T {
val v = map[p.name] as T; println("read ${p.name}=$v"); return v
}
override fun setValue(t:Any?,p:KProperty<*>,value:T) {
println("write ${p.name}=$value"); map[p.name]=value
}
}
var host: String by Delegate()
}
fun main() { val m=TrackedMap(); m.host="localhost"; println(m.host) }SharedPreferences-Style Delegate
A delegate that stores values in a backing map simulating SharedPreferences — adapt to real Android prefs by swapping the map for actual prefs calls.
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
val prefs = mutableMapOf<String, Any?>()
fun <T> pref(default: T): ReadWriteProperty<Any?, T> = object : ReadWriteProperty<Any?, T> {
@Suppress("UNCHECKED_CAST")
override fun getValue(t: Any?, p: KProperty<*>): T = prefs.getOrDefault(p.name, default) as T
override fun setValue(t: Any?, p: KProperty<*>, value: T) { prefs[p.name] = value }
}
object UserPrefs {
var username: String by pref("Guest")
var isDarkMode: Boolean by pref(false)
}
fun main() {
println(UserPrefs.username) // Guest
UserPrefs.username = "Alice"
println(UserPrefs.username) // Alice
}Typed Preference Helpers
Create typed helper functions for each primitive preference type for cleaner call sites.
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
val store = mutableMapOf<String,Any?>()
fun stringPref(default: String) = object : ReadWriteProperty<Any?,String> {
@Suppress("UNCHECKED_CAST")
override fun getValue(t:Any?,p:KProperty<*>) = store.getOrDefault(p.name, default) as String
override fun setValue(t:Any?,p:KProperty<*>,v:String) { store[p.name]=v }
}
fun intPref(default: Int) = object : ReadWriteProperty<Any?,Int> {
@Suppress("UNCHECKED_CAST")
override fun getValue(t:Any?,p:KProperty<*>) = store.getOrDefault(p.name, default) as Int
override fun setValue(t:Any?,p:KProperty<*>,v:Int) { store[p.name]=v }
}
object Prefs {
var name: String by stringPref("default")
var count: Int by intPref(0)
}
fun main() { Prefs.name="Bob"; Prefs.count=5; println("${Prefs.name}: ${Prefs.count}") }Audit Log Delegate
Record every property mutation with timestamp to an audit list — ideal for compliance or debugging scenarios.
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
val audit = mutableListOf<String>()
class AuditDelegate<T>(private var v: T) : ReadWriteProperty<Any?, T> {
override fun getValue(t:Any?,p:KProperty<*>) = v
override fun setValue(t:Any?,p:KProperty<*>,value:T) {
audit += "[${System.currentTimeMillis()}] ${p.name}: $v -> $value"
v = value
}
}
var price: Double by AuditDelegate(9.99)
fun main() {
price = 12.99
price = 11.49
audit.forEach(::println)
}Validation + Map Storage
Combine map storage with validation: reject invalid values before writing to the map.
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
val data = mutableMapOf<String, Any?>()
fun positiveInt(default: Int): ReadWriteProperty<Any?,Int> = object : ReadWriteProperty<Any?,Int> {
@Suppress("UNCHECKED_CAST")
override fun getValue(t:Any?,p:KProperty<*>)=data.getOrDefault(p.name,default) as Int
override fun setValue(t:Any?,p:KProperty<*>,v:Int){
require(v>=0){"${p.name} must be >= 0"}
data[p.name]=v
}
}
object Inventory { var stock: Int by positiveInt(100) }
fun main(){
Inventory.stock=50; println(Inventory.stock)
try { Inventory.stock=-1 } catch(e:Exception){ println(e.message) }
}Delegate Composition Pattern
Compose multiple delegate behaviors using a builder-style API: start with a base delegate and layer on logging, validation, or caching.
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
fun <T> ReadWriteProperty<Any?,T>.withLogging(): ReadWriteProperty<Any?,T> {
val base = this
return object : ReadWriteProperty<Any?,T> {
override fun getValue(t:Any?,p:KProperty<*>): T {
val v = base.getValue(t,p); println("get ${p.name}=$v"); return v
}
override fun setValue(t:Any?,p:KProperty<*>,v:T){
println("set ${p.name}=$v"); base.setValue(t,p,v)
}
}
}Real-World: Config Object Pattern
Use map delegation to build a configuration object from external sources like environment variables or a JSON config file.
class AppConfig(private val raw: Map<String, Any?>) {
val host: String by raw
val port: Int by raw
val debug: Boolean by raw
}
fun main() {
val env = mapOf("host" to "0.0.0.0", "port" to 8080, "debug" to true)
val cfg = AppConfig(env)
println("${cfg.host}:${cfg.port} debug=${cfg.debug}")
}Quick Check
What happens when you delegate a property to a Map?
Recap
Delegates unlock powerful patterns: map delegation for dynamic/JSON data, SharedPreferences-style persistence, audit logging for compliance, and composable validation — all without changing call sites.
Frequently asked questions
Is the “Delegates for Preferences, Map-Backed Properties & Logging” lesson free?
Yes — the full text of “Delegates for Preferences, Map-Backed Properties & Logging” 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 “Delegates for Preferences, Map-Backed Properties & Logging”?
Apply delegates to SharedPreferences, Map storage, and audit logging. 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 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Delegates for Preferences, Map-Backed Properties & Logging” 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
- by lazy: Deferred Initialization Deep Dive
- observable and vetoable Delegates
- Writing a Custom ReadWriteProperty Delegate
- Delegates for Preferences, Map-Backed Properties & Logging