Share
Embed
Delightful Delegate Design (Kotlin Budapest User Group meetup - April)
When developing a library, designing an easy to use API while hiding unnecessary implementation details from clients is fundamental. This talk and article looks at some of the API design choices we’ve made for our library Krate, an Android SharedPreferences wrapper.
Talk recording: https://www.youtube.com/watch?v=jTmHNo48zs0
Márton Braun
April 11, 2019
Transcript
88 slides
-
val reader = BufferedReader(...) reader.use { val line = it.readLine()
// ... } with(user) { println(name) } val oneToOne: Pair<Int, String> = 1 to "one" -
val pi: Double by lazy { val sum = (1..50_000).sumByDouble
{ 1.0 / (it * it) } sqrt(sum * 6.0) } println(pi) println(pi) val reader = BufferedReader(...) reader.use { val line = it.readLine() // ... } with(user) { println(name) } val oneToOne: Pair<Int, String> = 1 to "one" -
val pi: Double by val sum = (1..50_000).sumByDouble { 1.0
/ (it * it) } sqrt(sum * 6.0) println(pi) println(pi) lazy } { -
val pi: Double by val sum = (1..50_000).sumByDouble { 1.0
/ (it * it) } sqrt(sum * 6.0) println(pi) println(pi) lazy } { https://forums.swift.org/t/pitch-property-delegates/21895 -
val pi: Double by val sum = (1..50_000).sumByDouble { 1.0
/ (it * it) } sqrt(sum * 6.0) println(pi) println(pi) LazyDelegate( }) { -
class Constants { private var pi_: Double? = null val
pi: Double get() { if (pi_ == null) { val sum = (1..50_000).sumByDouble { 1.0 / (it * it) } pi_ = sqrt(sum * 6.0) } return pi_!! } private var e_: Double? = null val e: Double get() { if (e_ == null) { val sum = (0..20).sumByDouble { 1.0 / (1..it).fold(1, { a, x -> a * x }) } e_ = sum } return e_!! } } -
class Constants { private var pi_: Double? = null val
pi: Double get() { if (pi_ == null) { val sum = (1..50_000).sumByDouble { 1.0 / (it * it) } pi_ = sqrt(sum * 6.0) } return pi_!! } private var e_: Double? = null val e: Double get() { if (e_ == null) { val sum = (0..20).sumByDouble { 1.0 / (1..it).fold(1, { a, x -> a * x }) } e_ = sum } return e_!! } } -
class Constants { private var pi_: Double? = null val
pi: Double get() { if (pi_ == null) { val sum = (1..50_000).sumByDouble { 1.0 / (it * it) } pi_ = sqrt(sum * 6.0) } return pi_!! } private var e_: Double? = null val e: Double get() { if (e_ == null) { val sum = (0..20).sumByDouble { 1.0 / (1..it).fold(1, { a, x -> a * x }) } e_ = sum } return e_!! } } -
class Constants { private var pi_: Double? = null val
pi: Double get() { if (pi_ == null) { val sum = (1..50_000).sumByDouble { 1.0 / (it * it) } pi_ = sqrt(sum * 6.0) } return pi_!! } private var e_: Double? = null val e: Double get() { if (e_ == null) { val sum = (0..20).sumByDouble { 1.0 / (1..it).fold(1, { a, x -> a * x }) } e_ = sum } return e_!! } } -
val pi: Double by LazyDelegate({ val sum = (1..50_000).sumByDouble {
1.0 / (it * it) } sqrt(sum * 6.0) }) println(pi) println(pi) -
val pi: Double by LazyDelegate({ val sum = (1..50_000).sumByDouble {
1.0 / (it * it) } sqrt(sum * 6.0) }) println(pi) println(pi) class LazyDelegate<T : Any>(private val initializer: () -> T) { } -
val pi: Double by LazyDelegate({ val sum = (1..50_000).sumByDouble {
1.0 / (it * it) } sqrt(sum * 6.0) }) println(pi) println(pi) class LazyDelegate<T : Any>(private val initializer: () -> T) { } operator fun getValue(thisRef: Any?, property: KProperty<*>): T { } -
val pi: Double by LazyDelegate({ val sum = (1..50_000).sumByDouble {
1.0 / (it * it) } sqrt(sum * 6.0) }) println(pi) println(pi) class LazyDelegate<T : Any>(private val initializer: () -> T) { } operator fun getValue(thisRef: Any?, property: KProperty<*>): T { } private var value: T? = null -
class LazyDelegate<T : Any>(private val initializer: () -> T) {
} val pi: Double by LazyDelegate({ val sum = (1..50_000).sumByDouble { 1.0 / (it * it) } sqrt(sum * 6.0) }) println(pi) println(pi) operator fun getValue(thisRef: Any?, property: KProperty<*>): T { } private var value: T? = null if (value == null) { value = initializer() } return value!! -
val pi: Double by LazyDelegate({ val sum = (1..50_000).sumByDouble {
1.0 / (it * it) } sqrt(sum * 6.0) }) println(pi) // 12597400 ns println(pi) // 72100 ns class LazyDelegate<T : Any>(private val initializer: () -> T) { private var value: T? = null operator fun getValue(thisRef: Any?, property: KProperty<*>): T { if (value == null) { value = initializer() } return value!! } } -
val pi: Double by LazyDelegate({ val sum = (1..50_000).sumByDouble {
1.0 / (it * it) } sqrt(sum * 6.0) }) println(pi) // 12597400 ns println(pi) // 72100 ns class LazyDelegate<T : Any>(private val initializer: () -> T) { private var value: T? = null operator fun getValue(thisRef: Any?, property: KProperty<*>): T { if (value == null) { value = initializer() } return value!! } } -
val pi: Double by LazyDelegate { val sum = (1..50_000).sumByDouble
{ 1.0 / (it * it) } sqrt(sum * 6.0) } println(pi) // 12597400 ns println(pi) // 72100 ns class LazyDelegate<T : Any>(private val initializer: () -> T) { private var value: T? = null operator fun getValue(thisRef: Any?, property: KProperty<*>): T { if (value == null) { value = initializer() } return value!! } } -
val pi: Double by lazy { val sum = (1..50_000).sumByDouble
{ 1.0 / (it * it) } sqrt(sum * 6.0) } println(pi) // 12597400 ns println(pi) // 72100 ns class LazyDelegate<T : Any>(private val initializer: () -> T) { private var value: T? = null operator fun getValue(thisRef: Any?, property: KProperty<*>): T { if (value == null) { value = initializer() } return value!! } } -
val pi: Double by lazy { val sum = (1..50_000).sumByDouble
{ 1.0 / (it * it) } sqrt(sum * 6.0) } println(pi) // 12597400 ns println(pi) // 72100 ns class lazy<T : Any>(private val initializer: () -> T) { private var value: T? = null operator fun getValue(thisRef: Any?, property: KProperty<*>): T { if (value == null) { value = initializer() } return value!! } } -
val pi: Double by lazy { val sum = (1..50_000).sumByDouble
{ 1.0 / (it * it) } sqrt(sum * 6.0) } println(pi) // 12597400 ns println(pi) // 72100 ns class LazyDelegate<T : Any>(private val initializer: () -> T) { private var value: T? = null operator fun getValue(thisRef: Any?, property: KProperty<*>): T { if (value == null) { value = initializer() } return value!! } } -
fun <T : Any> lazy(initializer: () -> T) = LazyDelegate(initializer)
class LazyDelegate<T : Any>(private val initializer: () -> T) { private var value: T? = null operator fun getValue(thisRef: Any?, property: KProperty<*>): T { if (value == null) { value = initializer() } return value!! } } val pi: Double by lazy { val sum = (1..50_000).sumByDouble { 1.0 / (it * it) } sqrt(sum * 6.0) } println(pi) // 12597400 ns println(pi) // 72100 ns -
krate interface Krate { val sharedPreferences: SharedPreferences } abstract class
SimpleKrate(context: Context) : Krate { override val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) } -
krate interface Krate { val sharedPreferences: SharedPreferences } abstract class
SimpleKrate(context: Context) : Krate { override val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) } app -
app krate class MyKrate(context: Context) : SimpleKrate(context) { var onboarded
by booleanPref("onboarded") var appOpenCount by intPref("appOpenCount") var username by stringPref("username") } myKrate.onboarded = true myKrate.appOpenCount++ myKrate.username = "t1gg3r" interface Krate { val sharedPreferences: SharedPreferences } abstract class SimpleKrate(context: Context) : Krate { override val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) } -
krate app interface Krate { val sharedPreferences: SharedPreferences } class
MyKrate(context: Context) : SimpleKrate(context) { } -
krate app interface Krate { val sharedPreferences: SharedPreferences } class
MyKrate(context: Context) : SimpleKrate(context) { var score: Int by ??? } -
app krate interface Krate { val sharedPreferences: SharedPreferences } class
MyKrate(context: Context) : SimpleKrate(context) { var score: Int by ??? } println(myKrate.score) // 0 myKrate.score = 34 println(myKrate.score) // 34 -
app krate interface Krate { val sharedPreferences: SharedPreferences } class
MyKrate(context: Context) : SimpleKrate(context) { var score: Int by ??? } println(myKrate.score) // 0 myKrate.score = 34 println(myKrate.score) // 34 class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) { } -
krate app interface Krate { val sharedPreferences: SharedPreferences } class
MyKrate(context: Context) : SimpleKrate(context) { var score: Int by ??? } println(myKrate.score) // 0 myKrate.score = 34 println(myKrate.score) // 34 class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) { } -
app krate interface Krate { val sharedPreferences: SharedPreferences } class
IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) { operator fun getValue(thisRef: Any?, property: KProperty<*>): Int { } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { } } class MyKrate(context: Context) : SimpleKrate(context) { var score: Int by ??? } println(myKrate.score) // 0 myKrate.score = 34 println(myKrate.score) // 34 -
app krate interface Krate { val sharedPreferences: SharedPreferences } class
IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) { operator fun getValue(thisRef: Any?, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } class MyKrate(context: Context) : SimpleKrate(context) { var score: Int by ??? } println(myKrate.score) // 0 myKrate.score = 34 println(myKrate.score) // 34 -
app krate interface Krate { val sharedPreferences: SharedPreferences } class
IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) { operator fun getValue(thisRef: Any?, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } class MyKrate(context: Context) : SimpleKrate(context) { var score: Int by ??? } println(myKrate.score) // 0 myKrate.score = 34 println(myKrate.score) // 34 -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by IntDelegate(sharedPreferences, "score") } krate interface Krate { val sharedPreferences: SharedPreferences } class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) { operator fun getValue(thisRef: Any?, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } } println(myKrate.score) // 0 myKrate.score = 34 println(myKrate.score) // 34 -
app krate interface Krate { val sharedPreferences: SharedPreferences } class
IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) { operator fun getValue(thisRef: Any?, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } class MyKrate(context: Context) : SimpleKrate(context) { var score: Int by IntDelegate(sharedPreferences, "score") } fun Krate.intPref(key: String): IntDelegate { return IntDelegate(sharedPreferences, key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate interface Krate { val sharedPreferences: SharedPreferences } class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) { operator fun getValue(thisRef: Any?, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } fun Krate.intPref(key: String): IntDelegate { return IntDelegate(sharedPreferences, key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate interface Krate { val sharedPreferences: SharedPreferences } class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) { operator fun getValue(thisRef: Any?, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } fun Krate.intPref(key: String): IntDelegate { return IntDelegate(sharedPreferences, key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate interface Krate { val sharedPreferences: SharedPreferences } internal class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) { operator fun getValue(thisRef: Any?, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } fun Krate.intPref(key: String): IntDelegate { return IntDelegate(sharedPreferences, key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate public interface Krate { public val sharedPreferences: SharedPreferences } internal class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) { operator fun getValue(thisRef: Any?, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } public fun Krate.intPref(key: String): IntDelegate { return IntDelegate(sharedPreferences, key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate public interface Krate { public val sharedPreferences: SharedPreferences } internal class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) { operator fun getValue(thisRef: Any?, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } public fun Krate.intPref(key: String): IntDelegate { return IntDelegate(sharedPreferences, key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate public interface Krate { public val sharedPreferences: SharedPreferences } internal class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) { operator fun getValue(thisRef: Any?, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } public fun Krate.intPref(key: String): IntDelegate { return IntDelegate(sharedPreferences, key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate public interface Krate { public val sharedPreferences: SharedPreferences } internal class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) { operator fun getValue(thisRef: Any?, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } public fun Krate.intPref(key: String): IntDelegate { return IntDelegate(sharedPreferences, key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate public interface Krate { public val sharedPreferences: SharedPreferences } internal class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) : ReadWriteProperty<Krate, Int> { operator fun getValue(thisRef: Any?, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } public fun Krate.intPref(key: String): IntDelegate { return IntDelegate(sharedPreferences, key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate public interface Krate { public val sharedPreferences: SharedPreferences } internal class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) : ReadWriteProperty<Krate, Int> { override operator fun getValue(thisRef: Any?, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } public fun Krate.intPref(key: String): IntDelegate { return IntDelegate(sharedPreferences, key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate public interface Krate { public val sharedPreferences: SharedPreferences } internal class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) : ReadWriteProperty<Krate, Int> { override operator fun getValue(thisRef: Any?, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } public fun Krate.intPref(key: String): IntDelegate { return IntDelegate(sharedPreferences, key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate public interface Krate { public val sharedPreferences: SharedPreferences } internal class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) : ReadWriteProperty<Krate, Int> { override operator fun getValue(thisRef: Any?, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } public fun Krate.intPref(key: String): IntDelegate { return IntDelegate(sharedPreferences, key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate public interface Krate { public val sharedPreferences: SharedPreferences } internal class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) : ReadWriteProperty<Krate, Int> { override operator fun getValue(thisRef: Any?, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } public fun Krate.intPref(key: String): IntDelegate { return IntDelegate(sharedPreferences, key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate public interface Krate { public val sharedPreferences: SharedPreferences } internal class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) : ReadWriteProperty<Krate, Int> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } override operator fun setValue(thisRef: Krate, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } public fun Krate.intPref(key: String): IntDelegate { return IntDelegate(sharedPreferences, key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate public interface Krate { public val sharedPreferences: SharedPreferences } internal class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) : ReadWriteProperty<Krate, Int> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } override operator fun setValue(thisRef: Krate, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } public fun Krate.intPref(key: String): IntDelegate { return IntDelegate(sharedPreferences, key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate public interface Krate { public val sharedPreferences: SharedPreferences } internal class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) : ReadWriteProperty<Krate, Int> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): Int { return sharedPreferences.getInt(key, 0) } override operator fun setValue(thisRef: Krate, property: KProperty<*>, value: Int) { sharedPreferences.edit().putInt(key, value).apply() } } public fun Krate.intPref(key: String): IntDelegate { return IntDelegate(sharedPreferences, key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate public interface Krate { public val sharedPreferences: SharedPreferences } internal class IntDelegate( private val sharedPreferences: SharedPreferences, private val key: String ) : ReadWriteProperty<Krate, Int> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): Int { return thisRef.sharedPreferences.getInt(key, 0) } override operator fun setValue(thisRef: Krate, property: KProperty<*>, value: Int) { thisRef.sharedPreferences.edit().putInt(key, value).apply() } } public fun Krate.intPref(key: String): IntDelegate { return IntDelegate(sharedPreferences, key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate public interface Krate { public val sharedPreferences: SharedPreferences } internal class IntDelegate( private val key: String ) : ReadWriteProperty<Krate, Int> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): Int { return thisRef.sharedPreferences.getInt(key, 0) } override operator fun setValue(thisRef: Krate, property: KProperty<*>, value: Int) { thisRef.sharedPreferences.edit().putInt(key, value).apply() } } public fun Krate.intPref(key: String): IntDelegate { return IntDelegate(key) } -
app class MyKrate(context: Context) : SimpleKrate(context) { var score: Int
by intPref("score") } krate public interface Krate { public val sharedPreferences: SharedPreferences } internal class IntDelegate( private val key: String ) : ReadWriteProperty<Krate, Int> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): Int { return thisRef.sharedPreferences.getInt(key, 0) } override operator fun setValue(thisRef: Krate, property: KProperty<*>, value: Int) { thisRef.sharedPreferences.edit().putInt(key, value).apply() } } public fun Krate.intPref(key: String): ReadWriteProperty<Krate, Int> { return IntDelegate(key) } -
app krate public interface Krate { public val sharedPreferences: SharedPreferences
} class MyKrate(context: Context) : SimpleKrate(context) { var users: List<User>? by ??? } myKrate.users = listOf(User("William"), User("Virginia")) println(myKrate.users) -
app krate public interface Krate { public val sharedPreferences: SharedPreferences
} class MyKrate(context: Context) : SimpleKrate(context) { va users: List<User>? by gsonPref("users") } myKrate.users = listOf(User("William"), User("Virginia")) println(myKrate.users) r -
app krate public interface Krate { public val sharedPreferences: SharedPreferences
} class MyKrate(context: Context) : SimpleKrate(context) { va users: List<User>? by gsonPref("users") } myKrate.users = listOf(User("William"), User("Virginia")) println(myKrate.users) l -
app myKrate.users = listOf(User("William"), User("Virginia")) println(myKrate.users) class MyKrate(context: Context) :
SimpleKrate(context) { val users: List<User>? by gsonPref("users") } krate public interface Krate { public val sharedPreferences: SharedPreferences } internal class GsonDelegate<T : Any>( private val key: String ) : ReadOnlyProperty<Krate, T?> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): T? { val string = thisRef.sharedPreferences.getString(key, null) return Gson().fromJson(string, object : TypeToken<T>() {}.type) } } -
app krate public interface Krate { public val sharedPreferences: SharedPreferences
} class MyKrate(context: Context) : SimpleKrate(context) { val users: List<User>? by gsonPref("users") } internal class GsonDelegate<T : Any>( private val key: String ) : ReadOnlyProperty<Krate, T?> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): T? { val string = thisRef.sharedPreferences.getString(key, null) return Gson().fromJson(string, object : TypeToken<T>() {}.type) } } public fun <T : Any> Krate.gsonPref( key: String ): ReadOnlyProperty<Krate, T?> { return GsonDelegate(key) } -
app krate public interface Krate { public val sharedPreferences: SharedPreferences
} class MyKrate(context: Context) : SimpleKrate(context) { val users: List<User>? by gsonPref("users") } internal class GsonDelegate<Object>( private val key: String ) : ReadOnlyProperty<Krate, Object?> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): Object? { val string = thisRef.sharedPreferences.getString(key, null) return Gson().fromJson(string, object : TypeToken<Object>() {}.type) } } public fun <Object> Krate.gsonPref( key: String ): ReadOnlyProperty<Krate, Object?> { return GsonDelegate(key) } -
app krate public interface Krate { public val sharedPreferences: SharedPreferences
} class MyKrate(context: Context) : SimpleKrate(context) { val users: List<User>? by gsonPref("users") } internal class GsonDelegate<T : Any>( private val key: String ) : ReadOnlyProperty<Krate, T?> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): T? { val string = thisRef.sharedPreferences.getString(key, null) return Gson().fromJson(string, object : TypeToken<T>() {}.type) } } public fun <T : Any> Krate.gsonPref( key: String ): ReadOnlyProperty<Krate, T?> { return GsonDelegate(key) } -
app krate public interface Krate { public val sharedPreferences: SharedPreferences
} class MyKrate(context: Context) : SimpleKrate(context) { val users: List<User>? by gsonPref("users") } public inline fun <reified T : Any> Krate.gsonPref( key: String ): ReadOnlyProperty<Krate, T?> { return GsonDelegate(key) } object : TypeToken<T>() {}.type) ) : ReadOnlyProperty<Krate, T?> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): T? { val string = thisRef.sharedPreferences.getString(key, null) return Gson().fromJson(string, } } internal class GsonDelegate<T : Any>( private val key: String -
app gsonPref("users") class MyKrate(context: Context) : SimpleKrate(context) { val users:
List<User>? by } krate public interface Krate { public val sharedPreferences: SharedPreferences } public inline fun <reified T : Any> Krate.gsonPref( key: String ): ReadOnlyProperty<Krate, T?> { return GsonDelegate(key, object : TypeToken<T>() {}.type) } object : TypeToken<T>() {}.type) ) : ReadOnlyProperty<Krate, T?> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): T? { val string = thisRef.sharedPreferences.getString(key, null) return Gson().fromJson(string, } } internal class GsonDelegate<T : Any>( private val key: String -
app class MyKrate(context: Context) : SimpleKrate(context) { val users: List<User>?
by } gsonPref("users") krate public interface Krate { public val sharedPreferences: SharedPreferences } public inline fun <reified T : Any> Krate.gsonPref( key: String ): ReadOnlyProperty<Krate, T?> { return GsonDelegate(key, object : TypeToken<T>() {}.type) } ) : ReadOnlyProperty<Krate, T?> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): T? { val string = thisRef.sharedPreferences.getString(key, null) return Gson().fromJson(string, } } , private val type: Type type) internal class GsonDelegate<T : Any>( private val key: String -
app krate public interface Krate { public val sharedPreferences: SharedPreferences
} public inline fun <reified T : Any> Krate.gsonPref( key: String ): ReadOnlyProperty<Krate, T?> { return GsonDelegate(key, object : TypeToken<T>() {}.type) } GsonDelegate(key, object : TypeToken<T>() {}.type) class MyKrate(context: Context) : SimpleKrate(context) { val users: List<User>? by } gsonPref("users") ) : ReadOnlyProperty<Krate, T?> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): T? { val string = thisRef.sharedPreferences.getString(key, null) return Gson().fromJson(string, } } , private val type: Type type) internal class GsonDelegate<T : Any>( private val key: String -
app class MyKrate(context: Context) : SimpleKrate(context) { val users: List<User>?
by } GsonDelegate( , object : TypeToken< >() {}.type) "users" gsonPref("users") krate public interface Krate { public val sharedPreferences: SharedPreferences } public inline fun <reified T : Any> Krate.gsonPref( key: String ): ReadOnlyProperty<Krate, T?> { return GsonDelegate(key, object : TypeToken<T>() {}.type) } ) : ReadOnlyProperty<Krate, T?> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): T? { val string = thisRef.sharedPreferences.getString(key, null) return Gson().fromJson(string, } } , private val type: Type type) internal class GsonDelegate<T : Any>( private val key: String T -
app GsonDelegate( , object : TypeToken< >() {}.type) "users" List<User>
gsonPref("users") krate public interface Krate { public val sharedPreferences: SharedPreferences } public inline fun <reified T : Any> Krate.gsonPref( key: String ): ReadOnlyProperty<Krate, T?> { return GsonDelegate(key, object : TypeToken<T>() {}.type) } class MyKrate(context: Context) : SimpleKrate(context) { val users: List<User>? by } ) : ReadOnlyProperty<Krate, T?> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): T? { val string = thisRef.sharedPreferences.getString(key, null) return Gson().fromJson(string, } } , private val type: Type type) internal class GsonDelegate<T : Any>( private val key: String -
app gsonPref("users") class MyKrate(context: Context) : SimpleKrate(context) { val users:
List<User>? by } krate public interface Krate { public val sharedPreferences: SharedPreferences } public inline fun <reified T : Any> Krate.gsonPref( key: String ): ReadOnlyProperty<Krate, T?> { return GsonDelegate(key, object : TypeToken<T>() {}.type) } ) : ReadOnlyProperty<Krate, T?> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): T? { val string = thisRef.sharedPreferences.getString(key, null) return Gson().fromJson(string, } } , private val type: Type type) internal class GsonDelegate<T : Any>( private val key: String -
app gsonPref("users") krate public interface Krate { public val sharedPreferences:
SharedPreferences } public inline fun <reified T : Any> Krate.gsonPref( key: String ): ReadOnlyProperty<Krate, T?> { return GsonDelegate(key, object : TypeToken<T>() {}.type) } ) : ReadOnlyProperty<Krate, T?> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): T? { val string = thisRef.sharedPreferences.getString(key, null) return Gson().fromJson(string, } } , private val type: Type type) internal class GsonDelegate<T : Any>( private val key: String class MyKrate(context: Context) : SimpleKrate(context) { val users: List<User>? by } -
app class MyKrate(context: Context) : SimpleKrate(context) { val users: List<User>?
by } gsonPref("users") GsonDelegate(...) krate public interface Krate { public val sharedPreferences: SharedPreferences } public inline fun <reified T : Any> Krate.gsonPref( key: String ): ReadOnlyProperty<Krate, T?> { return GsonDelegate(key, object : TypeToken<T>() {}.type) } ) : ReadOnlyProperty<Krate, T?> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): T? { val string = thisRef.sharedPreferences.getString(key, null) return Gson().fromJson(string, } } , private val type: Type type) internal class GsonDelegate<T : Any>( private val key: String -
app krate public interface Krate { public val sharedPreferences: SharedPreferences
} class MyKrate(context: Context) : SimpleKrate(context) { val users: List<User>? by gsonPref("users") } @PublishedApi internal class GsonDelegate<T : Any>( private val key: String, private val type: Type ) : ReadOnlyProperty<Krate, T?> { override operator fun getValue(thisRef: Krate, property: KProperty<*>): T? { val string = thisRef.sharedPreferences.getString(key, null) return Gson().fromJson(string, type) } } public inline fun <reified T : Any> Krate.gsonPref( key: String ): ReadOnlyProperty<Krate, T?> { return GsonDelegate(key, object : TypeToken<T>() {}.type) } -
Krate* class MyKrate(context: Context) : SimpleKrate(context) { var onboarded var
appOpenCount var username } myKrate.onboarded = true myKrate.appOpenCount++ println(myKrate.username) by booleanPref("onboarded" by intPref("appOpenCount" by stringPref("username" ) ) ) -
class MyKrate(context: Context) : SimpleKrate(context) { var onboarded: Boolean by
booleanPref("onboarded", defaultValue = false) var appOpenCount: Int by intPref("appOpenCount", defaultValue = 0) var username: String? by stringPref("username") } Krate* myKrate.onboarded = true myKrate.appOpenCount++ println(myKrate.username) -
class MyKrate(context: Context) : SimpleKrate(context) { // non-nullable, has default
value var onboarded: Boolean by booleanPref("onboarded", defaultValue = false) var appOpenCount: Int by intPref("appOpenCount", defaultValue = 0) // nullable, null by default var username: String? by stringPref("username") } Krate* myKrate.onboarded = true myKrate.appOpenCount++ println(myKrate.username) -
class MyKrate(context: Context) : SimpleKrate(context { // non-nullable, has default
value var onboarded: Boolean by booleanPref("onboarded", defaultValue = false) var appOpenCount: Int by intPref("appOpenCount", defaultValue = 0) // nullable, null by default var username: String? by stringPref("username") } Krate* myKrate.onboarded = true myKrate.appOpenCount++ println(myKrate.username) ) -
Krate* myKrate.onboarded = true myKrate.appOpenCount++ println(myKrate.username) class MyKrate(context: Context) :
SimpleKrate(context , AppSettings { // non-nullable, has default value override var onboarded: Boolean by booleanPref("onboarded", defaultValue = false) override var appOpenCount: Int by intPref("appOpenCount", defaultValue = 0) // nullable, null by default override var username: String? by stringPref("username") } ) -
class MyKrate @Inject constructor(context: Context) // non-nullable, has default value
override var onboarded: Boolean by booleanPref("onboarded", defaultValue = false) override var appOpenCount: Int by intPref("appOpenCount", defaultValue = 0) // nullable, null by default override var username: String? by stringPref("username") } : SimpleKrate(context), AppSetti Krate* myKrate.onboarded = true myKrate.appOpenCount++ println(myKrate.username) -
class MyKrate @Inject constructor(context: Context) // non-nullable, has default value
override var onboarded: Boolean by booleanPref("onboarded", defaultValue = false) override var appOpenCount: Int by intPref("appOpenCount", defaultValue = 0) // nullable, null by default override var username: String? by stringPref("username") } Krate* myKrate.onboarded = true myKrate.appOpenCount++ println(myKrate.username) : SimpleKrate(context), AppSettings { -
References • Krate https://github.com/AutSoft/Krate • Delightful Delegate Design
https://blog.autsoft.hu/delightful-delegate-design/ • Further reading Maintaining Compatibility in Kotlin libraries https://zsmb.co/maintaining-compatibility-in-kotlin-libraries/ Swift Pitch: Property Delegates https://forums.swift.org/t/pitch-property-delegates/21895 DSL Design https://zsmb.co/kotlin-dsl-design-with-village-dsl/ Tips for writing a library https://www.kotlindevelopment.com/tips-for-writing-a-library-in-kotlin/