SlideShare a Scribd company logo
Kotlin delegates
in practice
Fabio Collini
@fabioCollini
“”
“The ratio of time spent reading (code)

versus writing is well over 10 to 1

(therefore) making it easy to read

makes it easier to write

Robert C. Martin
“”
“The Principle of Least Astonishment states that

the result of performing some operation should be
obvious, consistent, and predictable, based upon
the name of the operation and other clues

https://wiki.c2.com/?PrincipleOfLeastAstonishment
Kotlin code is readable
Data classes
Extension functions
Sealed classes
Coroutines
Delegates
…
Delegates
public class MyEquivalentJavaClass {
private final String property = slowMethod();
public String getProperty() {
return property;
}5
}6
class MyClass {
val property = slowMethod()
}1
public class MyEquivalentJavaClass {
private String property = slowMethod();
public String getProperty() {
return property;
}
public void setProperty(String var1) {
this.property = var1;
}5
}6
class MyClass {
var property = slowMethod()
}1
public class MyEquivalentJavaClass {
private String property = slowMethod();
}6
class MyClass {
private var property = slowMethod()
}1
public class MyEquivalentJavaClass {
public String getProperty() {
return slowMethod();
}5
}6
class MyClass {
val property get() = slowMethod()
}1
class MyClass {
val property = slowMethod()
}1
fun main() {
val obj = MyClass()
println(obj.property)A
println(obj.property)B
}2
class MyClass {
val property = slowMethod()
}1
fun main() {
println("starting")
val obj = MyClass()
println("obj created")
println(obj.property)A
println(obj.property)B
println("end")
}2
starting
slowMethod invoked
obj created
end
class MyClass {
val property get() = slowMethod()
}1
fun main() {
println("starting")
val obj = MyClass()
println("obj created")
println(obj.property)A
println(obj.property)B
println("end")
}2
starting
obj created
slowMethod invoked
slowMethod invoked
end
class MyClass {
val property by lazy {
slowMethod()
}3
}1
fun main() {
println("starting")
val obj = MyClass()
println("obj created")
println(obj.property)A
println(obj.property)B
println("end")
}2
starting
obj created
slowMethod invoked
end
class MyClass {
val property by lazy {
slowMethod()
}3
}1
by
public class MyEquivalentJavaClass {
private SimpleLazy lazy = new SimpleLazy(::slowMethod);
public String getProperty() {
return lazy.getValue();
}
}
internal object UNINITIALIZED_VALUE
class SimpleLazy<T>(private val initializer: () -> T) {
private var value: Any? = UNINITIALIZED_VALUE
fun getValue(): T {
if (value == UNINITIALIZED_VALUE) {
value = initializer()
}4
return value as T
}3
}2
/**
* Specifies how a Lazy instance synchronizes initialization among multiple threads.
*/
public enum class LazyThreadSafetyMode {
/**
* Locks are used to ensure that only a single thread can initialize the Lazy instance.
*/
SYNCHRONIZED,
/**
* Initializer function can be called several times on concurrent access to
* uninitialized Lazy instance value,
* but only the first returned value will be used as the value of Lazy instance.
*/
PUBLICATION,
/**
* No locks are used to synchronize an access to the Lazy instance value;
* if the instance is accessed from multiple threads, its behavior is undefined.
*
* This mode should not be used unless the Lazy instance is guaranteed never to
* be initialized from more than one thread.
*/
NONE
}
Default value
class MyClass {
val notAGoodIdea by lazy {
2 + 2
}3
}1
class MyClass {
suspend val property by lazy {
slowMethod()
}1
}2
suspend fun slowMethod() = withContext(IO) {
//...
}3
Modifier 'suspend' is not applicable to 'member property with delegate'
Suspend function 'slowMethod' should be called only from a coroutine or another suspend function
class MyFragment : Fragment() {
private val appName by lazy { getString(R.string.app_name) }1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
println("Starting $appName...")
}2
}3
Lazy
class MyFragment : Fragment() {
private lateinit var appName: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
appName = getString(R.string.app_name)
println("Starting $appName...")
}4
}5
lateinit
class MyFragment : Fragment() {
private lateinit var appName: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
appName = getString(R.string.app_name)
println("Starting $appName...")
}4
}5
lateinit
class MyFragment : Fragment() {
private val appName by lazy { getString(R.string.app_name) }1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
println("Starting $appName...")
}2
}3
Lazy
class MyFragment : Fragment() {
private lateinit var appName: String
private lateinit var title: String
private lateinit var summary: String
private lateinit var text: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
appName = getString(R.string.app_name)
title = getString(R.string.title)
summary = getString(R.string.summary)
text = "$appNamen$titlen$summary"
println(text)
}4
}5
lateinit class MyFragment2 : Fragment() {
private val appName by lazy { getString(R.string.app_name) }
private val title by lazy { getString(R.string.title) }
private val summary by lazy { getString(R.string.summary) }
private val text by lazy { "$appNamen$titlen$summary" }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
println(text)
}2
}3
Lazy
Custom
delegates
operator fun getValue(thisRef: Any, property: KProperty<*>): T
/**
* Base interface that can be used for implementing property delegates of read-only properties.
*1
* This is provided only for convenience; you don't have to extend this interface
* as long as your property delegate has methods with the same signatures.
*2
* @param R the type of object which owns the delegated property.
* @param T the type of the property value.
*/
interface ReadOnlyProperty<in R, out T> {
/**
* Returns the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @return the property value.
*/
operator fun getValue(thisRef: R, property: KProperty<*>): T
}3
class LogDelegate<T>(initialValue: T) : ReadOnlyProperty<Any, T> {
private var value: T = initialValue
override fun getValue(thisRef: Any, property: KProperty<*>): T {
println("get invoked on $thisRef.${property.name}")
return value
}1
}2
class LogDelegate<T>(initialValue: T) : ReadOnlyProperty<Any, T> {
private var value: T = initialValue
override fun getValue(thisRef: Any, property: KProperty<*>): T {
println("get invoked on $thisRef.${property.name}")
return value
}1
}2
class MyClass {
val property by LogDelegate("ABC")
}3
class LogDelegate<T>(initialValue: T) : ReadOnlyProperty<Any, T> {
private var value: T = initialValue
override fun getValue(thisRef: Any, property: KProperty<*>): T {
println("get invoked on $thisRef.${property.name}")
return value
}1
}2
class MyClass {
val property by LogDelegate("ABC")
}3
fun main() {
val obj = MyClass()
println(obj.property)
}4
get invoked on MyClass@87aac27.property
ABC
/**
* Base interface that can be used for implementing property delegates of read-write properties.
*
* This is provided only for convenience; you don't have to extend this interface
* as long as your property delegate has methods with the same signatures.
*
* @param R the type of object which owns the delegated property.
* @param T the type of the property value.
*/
interface ReadWriteProperty<in R, T> {
/**
* Returns the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @return the property value.
*/
operator fun getValue(thisRef: R, property: KProperty<*>): T
/**
* Sets the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @param value the value to set.
*/
operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}
class LogDelegate<T>(initialValue: T) : ReadWriteProperty<Any, T> {
private var value: T = initialValue
override fun getValue(thisRef: Any, property: KProperty<*>): T {
println("get invoked on $thisRef.${property.name}")
return value
}1
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
println("set invoked on $thisRef.${property.name} with value $value")
this.value = value
}5
}2
class MyClass {
var property by LogDelegate("ABC")
}3
fun main() {
val obj = MyClass()
println(obj.property)
obj.property = "DEF"
println(obj.property)
}4
get invoked on MyClass@e9e54c2.property
ABC
set invoked on MyClass@e9e54c2.property with value DEF
get invoked on MyClass@e9e54c2.property
DEF
A real
example
class TokenHolder(private val prefs: SharedPreferences) {
val token: String?
get() = prefs.getString(TOKEN, null)
val count: Int
get() = prefs.getInt(COUNT, 0)
fun saveToken(newToken: String) {
prefs.edit {
putString(TOKEN, newToken)
putInt(COUNT, count + 1)
}1
}2
companion object {
private const val TOKEN = "token"
private const val COUNT = "count"
}3
}4
class TokenHolder(private val prefs: SharedPreferences) {
val token: String?
get() = prefs.getString(TOKEN, null)
val count: Int
get() = prefs.getInt(COUNT, 0)
fun saveToken(newToken: String) {
prefs.edit {
putString(TOKEN, newToken)
putInt(COUNT, count + 1)
}1
}2
companion object {
private const val TOKEN = "token"
private const val COUNT = "count"
}3
}4
class TokenHolder(private val prefs: SharedPreferences) {
val token: String?
get() = prefs.getString(TOKEN, null)
val count: Int
get() = prefs.getInt(COUNT, 0)
fun saveToken(newToken: String) {
prefs.edit {
putString(TOKEN, newToken)
putInt(COUNT, count + 1)
}1
}2
companion object {
private const val TOKEN = "token"
private const val COUNT = "count"
}3
}4
class TokenHolder(private val prefs: SharedPreferences) {
val token: String?
get() = prefs.getString(TOKEN, null)
val count: Int
get() = prefs.getInt(COUNT, 0)
fun saveToken(newToken: String) {
prefs.edit {
putString(TOKEN, newToken)
putInt(COUNT, count + 1)
}1
}2
companion object {
private const val TOKEN = "token"
private const val COUNT = "count"
}3
}4
fun main() {
val tokenHolder = TokenHolder(sharedPreferences())
tokenHolder.saveToken("ABC")
println("${tokenHolder.token} - ${tokenHolder.count}")
tokenHolder.saveToken("DEF")
println("${tokenHolder.token} - ${tokenHolder.count}")
}
ABC - 1
DEF - 2
fun SharedPreferences.int() =
object : ReadWriteProperty<Any, Int> {
override fun getValue(thisRef: Any, property: KProperty<*>) =
getInt(property.name, 0)
override fun setValue(thisRef: Any, property: KProperty<*>, value: Int) =
edit { putInt(property.name, value) }
}1
fun SharedPreferences.int() =
object : ReadWriteProperty<Any, Int> {
override fun getValue(thisRef: Any, property: KProperty<*>) =
getInt(property.name, 0)
override fun setValue(thisRef: Any, property: KProperty<*>, value: Int) =
edit { putInt(property.name, value) }
}1
fun SharedPreferences.int(key: String, defaultValue: Int = 0) =
object : ReadWriteProperty<Any, Int> {
override fun getValue(thisRef: Any, property: KProperty<*>) =
getInt(key, defaultValue)
override fun setValue(thisRef: Any, property: KProperty<*>, value: Int) =
edit { putInt(key, value) }
}1
fun SharedPreferences.int(key: String, defaultValue: Int = 0) =
object : ReadWriteProperty<Any, Int> {
override fun getValue(thisRef: Any, property: KProperty<*>) =
getInt(key, defaultValue)
override fun setValue(thisRef: Any, property: KProperty<*>, value: Int) =
edit { putInt(key, value) }
}1
fun SharedPreferences.string(key: String, defaultValue: String? = null) =
object : ReadWriteProperty<Any, String?> {
override fun getValue(thisRef: Any, property: KProperty<*>) =
getString(key, defaultValue)
override fun setValue(thisRef: Any, property: KProperty<*>, value: String?) =
edit { putString(key, value) }
}2
class TokenHolder(private val prefs: SharedPreferences) {
val token: String?
get() = prefs.getString(TOKEN,0null)1
val count: Int
get() = prefs.getInt(COUNT, 0)
fun saveToken(newToken: String) {
prefs.edit {
putString(TOKEN, newToken)
putInt(COUNT, count + 1)
}1
}2
companion object {
private const val TOKEN = "token"
private const val COUNT = "count"
}3
}4
class TokenHolder(private val prefs: SharedPreferences) {
var token by prefs.string(TOKEN)1
private3set
val count: Int
get() = prefs.getInt(COUNT, 0)
fun saveToken(newToken: String) {
prefs.edit {
putString(TOKEN, newToken)
putInt(COUNT, count + 1)
}1
}2
companion object {
private const val TOKEN = "token"
private const val COUNT = "count"
}3
}4
class TokenHolder(private val prefs: SharedPreferences) {
var token by prefs.string(TOKEN)1
private set
val count: Int
get() = prefs.getInt(COUNT, 0)
fun saveToken(newToken: String) {
token = newToken
prefs.edit {
putInt(COUNT, count + 1)
}1
}2
companion object {
private const val TOKEN = "token"
private const val COUNT = "count"
}3
}4
class TokenHolder(private val prefs: SharedPreferences) {
var token by prefs.string("token")1
private set
val count: Int
get() = prefs.getInt(COUNT, 0)2
fun saveToken(newToken: String) {
token = newToken
prefs.edit {
putInt(COUNT, count + 1)
}1
}2
companion object {
private const val COUNT = "count"
}3
}4
class TokenHolder(private val prefs: SharedPreferences) {
var token by prefs.string("token")
private set
var count by prefs.int(COUNT)2
private set
fun saveToken(newToken: String) {
token = newToken
prefs.edit {
putInt(COUNT, count + 1)
}1
}2
companion object {
private const val COUNT = "count"
}3
}4
class TokenHolder(private val prefs: SharedPreferences) {
var token by prefs.string("token")
private set
var count by prefs.int(COUNT)2
private set
fun saveToken(newToken: String) {
token = newToken
count++
}2
companion object {
private const val COUNT = "count"
}3
}4
class TokenHolder(private val prefs: SharedPreferences) {
var token by prefs.string("token")
private set
var count by prefs.int("count")2
private set
fun saveToken(newToken: String) {
token = newToken
count++
}2
}4
class TokenHolder(prefs: SharedPreferences) {
var token by prefs.string("token")
private set
var count by prefs.int("count")
private set
fun saveToken(newToken: String) {
token = newToken
count++
}2
}4
prefs.edit {
putInt("count", prefs.getInt("count", 0) + 1)
}
class DemoFragment : Fragment() {
private val component by lazy {
//...
}
private val viewModel by viewModelProvider {
component.myViewModel()
}
//...
}
https://proandroiddev.com/kotlin-delegates-in-android-development-part-2-2c15c11ff438
class DemoFragment : Fragment() {
private var param1: Int by argument()
private var param2: String by argument()
companion object {
fun newInstance(param1: Int, param2: String): DemoFragment =
DemoFragment().apply {
this.param1 = param1
this.param2 = param2
}
}
}
https://proandroiddev.com/kotlin-delegates-in-android-1ab0a715762d
Standard
delegates
object AnalyticsLib {
fun trackEvent(event: Map<String, Any?>) {
println(event)
}1
}2
fun main() {
val event = mapOf(
"name" to "myEvent",
"value" to 123
)3
AnalyticsLib.trackEvent(event)
}4
fun main() {
val event = mapOf(
"name" to "myEvent",
"value" to 123
)3
AnalyticsLib.trackEvent(event)
}4
const val NAME = "name"
const val VALUE = "value"
fun main() {
val event = mapOf(
NAME to "myEvent",
VALUE to 123
)3
AnalyticsLib.trackEvent(event)
}4
const val NAME = "name"
const val VALUE = "value"
fun main() {
val event = mapOf(
NAME to "myEvent",
VALUE to "this should be an Int :("
)3
AnalyticsLib.trackEvent(event)
}4
class MyEvent {
val map: MutableMap<String, Any?> = mutableMapOf()
var name: String by map
var value: Int by map
}1
fun main() {
val event = MyEvent().apply {
name = "myEvent"
value = 123
}2
AnalyticsLib.trackEvent(event.map)
}3
data class MyEvent(val name: String, val value: Int) {
val map = mapOf(
"name" to name,
"value" to value
)
}1
fun main() {
val event = MyEvent(
name = "myEvent",
value = 123
)2
AnalyticsLib.trackEvent(event.map)
}3
object AbTestLib {
fun readValues() = mapOf<String, Any?>(
"featureEnabled" to true,
"delay" to 1000
)1
}2
object AbTestLib {
fun readValues() = mapOf<String, Any?>(
"featureEnabled" to true,
"delay" to 1000
)1
}2
fun main() {
val values = AbTestLib.readValues()
println(values["featureEnabled"] as Boolean)
println(values["delay"] as Int)
}3
true
1000
data class AbValues(private val map: Map<String, Any?>) {
val featureEnabled: Boolean by map
val delay: Int by map
}1
fun main() {
val values = AbValues(AbTestLib.readValues())
println(values.featureEnabled)
println(values.delay)
}2
data class AbValues(private val map: Map<String, Any?>) {
val featureEnabled: Boolean by map
val delay: Int by map
}1
fun main() {
val values = AbValues(
mapOf<String, Any?>(
"featureEnabled" to "true",
"delay" to "1000"
)
)
println(values.featureEnabled)
println(values.delay)
}2
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean
class User {
var name: String by Delegates.observable("<no name>") { prop, old, new ->
println("$old -> $new")
}
}
class User {
var name: String by Delegates.vetoable("<no name>") { prop, old, new ->
new.startsWith("f")
}
}
ObservableVetoable
class MyClass {
var myIntVar: Int by notNull()
fun onCreate() {
myIntVar = calculateValue()
}
}
notNull
Inheritance
Composition
Delegation
Inheritance
open class Class1 {
fun doSomething() = 123
}1
class Class2 : Class1()
Composition
class Class1 {
fun doSomething() = 123
}
class Class2 {
private val wrapped = Class1()
fun doSomething() = wrapped.doSomething()
}
Delegation
interface Interface1 {
fun doSomething(): Int
}4
class Class1 : Interface1 {
override fun doSomething() = 123
}5
class Class2(private val wrapped: Class1 = Class1())
: Interface1 by wrapped
Delegation
interface Interface1 {
fun doSomething(): Int
}4
class Class1 : Interface1 {
override fun doSomething() = 123
}5
class Class2 : Interface1 by Class1()
11
Delegation
interface Interface1 {
fun doSomething(): Int
}4
class Class1 : Interface1 {
override fun doSomething() = 123
}5
class Class2 : Interface1 by Class1()
fun main() {
val obj = Class2()
println(obj.doSomething())
}m
Composition
class Class1 {
fun doSomething() = 123
}2
class Class2 {
private val wrapped = Class1()
fun doSomething() =
wrapped.doSomething()
}3
Inheritance
open class Class1 {
fun doSomething() = 123
}1
class Class2 : Class1()
interface HasMargin {
val marginBottom: Int
val marginTop: Int
val marginLeft: Int
val marginRight: Int
}1
class Style(
val backgroundColor: Int,
override val marginBottom: Int,
override val marginTop: Int,
override val marginLeft: Int,
override val marginRight: Int
) : HasMargin
class View(style: Style) : HasMargin by style {
fun draw() {
//...
}
}
[
{
"type": "student",
"name": "studentName",
"surname": "studentSurname",
"age": 20,
"university": "universityName"
},
{
//...
}
]
data class PersonJson(
val type: String,
val name: String,
val surname: String,
val age: Int,
val university: String?,
val company: String?
)
abstract class Person(
val name: String,
val surname: String,
val age: Int
)
class Student(
name: String,
surname: String,
age: Int,
val university: String
) : Person(name, surname, age)
class Worker(
name: String,
surname: String,
age: Int,
val company: String
) : Person(name, surname, age)
fun main() {
val json: List<PersonJson> = listOf(/* ... */)
val people = json.map {
if (it.type == "student")
Student(
it.name,
it.surname,
it.age,
it.university!!
)
else
Worker(
it.name,
it.surname,
it.age,
it.company!!
)
}
println(people.joinToString { "${it.name} ${it.surname}" })
}
abstract class Person(
val_name: String,
val_surname: String,
val_age: Int
)
class Student(
name: String,
surname: String,
age: Int,
val university: String
) : Person(name, surname, age)_
class Worker(
name: String,
surname: String,
age: Int,
val company: String
) : Person(name, surname, age)_
abstract class Person {
abstract val_name: String
abstract val_surname: String
abstract val_age: Int
}1
data class Student(
override val name: String,
override val surname: String,
override val age: Int,
val university: String
) : Person()_
data class Worker(
override val name: String,
override val surname: String,
override val age: Int,
val company: String
) : Person()_
interface Person {
val name: String
val surname: String
val age: Int
}1
data class Student(
override val name: String,
override val surname: String,
override val age: Int,
val university: String
) : Person
data class Worker(
override val name: String,
override val surname: String,
override val age: Int,
val company: String
) : Person
interface Person {
val name: String
val surname: String
val age: Int
}1
interface Person {
val name: String
val surname: String
val age: Int
}1
data class PersonData(
override val name: String,
override val surname: String,
override val age: Int
) : Person
data class Student(
override val name: String,
override val surname: String,
override val age: Int,
val university: String
) : Person
data class Worker(
override val name: String,
override val surname: String,
override val age: Int,
val company: String
) : Person
data class Student(
override val name: String,
override val surname: String,
override val age: Int,
val university: String
) : Person
data class Worker(
override val name: String,
override val surname: String,
override val age: Int,
val company: String
) : Person
data class Student(
val data: PersonData,
val university: String
) : Person by data
data class Worker(
val data: PersonData,
val company: String
) : Person by data
fun main() {
val json: List<PersonJson> = listOf(/* ... */)
val people = json.map {
val data = PersonData(
it.name,
it.surname,
it.age
)
if (it.type == "student")
Student(data, it.university!!)
else
Worker(data, it.company!!)
}
println(people.joinToString { "${it.name} ${it.surname}" })
}
interface Person {
val name: String
val surname: String
val age: Int
}
data class Student(
override val name: String,
override val surname: String,
override val age: Int,
val university: String
) : Person
data class Worker(
override val name: String,
override val surname: String,
override val age: Int,
val company: String
) : Person
fun main() {
val json: List<PersonJson> = listOf(/* ... */)
val people = json.map {
if (it.type == "student")
Student(
it.name,
it.surname,
it.age,
it.university!!
)
else
Worker(
it.name,
it.surname,
it.age,
it.company!!
)
}
println(people.joinToString { "${it.name} ${it.surname}" })
}
interface Person {
val name: String
val surname: String
val age: Int
}
data class PersonData(
override val name: String,
override val surname: String,
override val age: Int
) : Person
data class Student(
val data: PersonData,
val university: String
) : Person by data
data class Worker(
val data: PersonData,
val company: String
) : Person by data
fun main() {
val json: List<PersonJson> = listOf(/* ... */)
val people = json.map {
val data = PersonData(
it.name,
it.surname,
it.age
)
if (it.type == "student")
Student(data, it.university!!)
else
Worker(data, it.company!!)
}
println(people.joinToString { "${it.name} ${it.surname}" })
}
DelegationInheritance
interface Person {
val name: String
val surname: String
val age: Int
val address: String
val city: String
val zipCode: String
val nation: String
val telephoneNumber1: String
val telephoneNumber2: String
val telephoneNumber3: String
}
data class Student(
override val name: String,
override val surname: String,
override val age: Int,
val university: String,
override val address: String,
override val city: String,
override val zipCode: String,
override val nation: String,
override val telephoneNumber1: String,
override val telephoneNumber2: String,
override val telephoneNumber3: String
) : Person
data class Worker(
override val name: String,
override val surname: String,
override val age: Int,
val company: String,
override val address: String,
override val city: String,
override val zipCode: String,
override val nation: String,
override val telephoneNumber1: String,
override val telephoneNumber2: String,
override val telephoneNumber3: String
) : Person
data class Unemployed(
override val name: String,
override val surname: String,
override val age: Int,
override val address: String,
override val city: String,
override val zipCode: String,
override val nation: String,
override val telephoneNumber1: String,
override val telephoneNumber2: String,
override val telephoneNumber3: String
) : Person
fun main() {
val json: List<PersonJson> = listOf(/* ... */)
val people = json.map {
if (it.type == "student")
Student(
it.name,
it.surname,
it.age,
it.university!!,
it.address,
it.city,
it.zipCode,
it.nation,
it.telephoneNumber1,
it.telephoneNumber2,
it.telephoneNumber3
)
else if (it.type == "worker")
Worker(
it.name,
it.surname,
it.age,
it.company!!,
it.address,
it.city,
it.zipCode,
it.nation,
it.telephoneNumber1,
it.telephoneNumber2,
it.telephoneNumber3
)
else
Unemployed(
it.name,
it.surname,
it.age,
it.address,
it.city,
it.zipCode,
it.nation,
it.telephoneNumber1,
it.telephoneNumber2,
it.telephoneNumber3
)
}
println(people.joinToString { "${it.name} ${it.surname}" })
}
interface Person {
val name: String
val surname: String
val age: Int
val address: String
val city: String
val zipCode: String
val nation: String
val telephoneNumber1: String
val telephoneNumber2: String
val telephoneNumber3: String
}
data class PersonData(
override val name: String,
override val surname: String,
override val age: Int,
override val address: String,
override val city: String,
override val zipCode: String,
override val nation: String,
override val telephoneNumber1: String,
override val telephoneNumber2: String,
override val telephoneNumber3: String
) : Person
data class Student(
val data: PersonData,
val university: String
) : Person by data
data class Worker(
val data: PersonData,
val company: String
) : Person by data
data class Unemployed(
val data: PersonData
) : Person by data
fun main() {
val json: List<PersonJson> = listOf(/* ... */)
val people = json.map {
val data = PersonData(
it.name,
it.surname,
it.age,
it.address,
it.city,
it.zipCode,
it.nation,
it.telephoneNumber1,
it.telephoneNumber2,
it.telephoneNumber3
)
if (it.type == "student")
Student(data, it.university!!)
else if (it.type == "worker")
Worker(data, it.company!!)
else
Unemployed(data)
}
println(people.joinToString { "${it.name} ${it.surname}" })
}
DelegationInheritance
Wrappingup
“”
“The ratio of time spent reading (code)

versus writing is well over 10 to 1

(therefore) making it easy to read

makes it easier to write

Robert C. Martin
Wrappingup
“”
“The Principle of Least Astonishment states that

the result of performing some operation should be
obvious, consistent, and predictable, based upon
the name of the operation and other clues

https://wiki.c2.com/?PrincipleOfLeastAstonishment
Wrappingup
Delegates can be useful to simplify code
but there are pros and cons!
Links&contacts
Simpler Kotlin class hierarchies using class delegation
proandroiddev.com/simpler-kotlin-class-hierarchies-using-class-delegation-35464106fed5
Kotlin delegates in Android development — Part 1
medium.com/hackernoon/kotlin-delegates-in-android-development-part-1-50346cf4aed7
Kotlin delegates in Android development — Part 2
proandroiddev.com/kotlin-delegates-in-android-development-part-2-2c15c11ff438
@fabioCollini
linkedin.com/in/fabiocollini
github.com/fabioCollini
medium.com/@fabioCollini
THANKS
FOR YOUR
ATTENTION
QUESTIONS?
@fabioCollini

More Related Content

What's hot

Protocol-Oriented MVVM (extended edition)
Protocol-Oriented MVVM (extended edition)Protocol-Oriented MVVM (extended edition)
Protocol-Oriented MVVM (extended edition)
Natasha Murashev
 
Swift Delhi: Practical POP
Swift Delhi: Practical POPSwift Delhi: Practical POP
Swift Delhi: Practical POP
Natasha Murashev
 
Anonymous functions in JavaScript
Anonymous functions in JavaScriptAnonymous functions in JavaScript
Anonymous functions in JavaScript
Mohammed Sazid Al Rashid
 
Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2
Fabio Collini
 
Practical Protocols with Associated Types
Practical Protocols with Associated TypesPractical Protocols with Associated Types
Practical Protocols with Associated Types
Natasha Murashev
 
Intro to Javascript
Intro to JavascriptIntro to Javascript
Intro to Javascript
Anjan Banda
 
Workshop 25: React Native - Components
Workshop 25: React Native - ComponentsWorkshop 25: React Native - Components
Workshop 25: React Native - Components
Visual Engineering
 
Protocol-Oriented MVVM
Protocol-Oriented MVVMProtocol-Oriented MVVM
Protocol-Oriented MVVM
Natasha Murashev
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React Alicante
Ignacio Martín
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
Codemotion
 
Workshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScriptWorkshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScript
Visual Engineering
 
Daggerate your code - Write your own annotation processor
Daggerate your code - Write your own annotation processorDaggerate your code - Write your own annotation processor
Daggerate your code - Write your own annotation processor
Bartosz Kosarzycki
 
Taming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, MacoscopeTaming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, Macoscope
Macoscope
 
Workshop 5: JavaScript testing
Workshop 5: JavaScript testingWorkshop 5: JavaScript testing
Workshop 5: JavaScript testing
Visual Engineering
 
Scientific calcultor-Java
Scientific calcultor-JavaScientific calcultor-Java
Scientific calcultor-Java
Shaibal Ahmed
 
Java final project of scientific calcultor
Java final project of scientific calcultorJava final project of scientific calcultor
Java final project of scientific calcultor
Md. Eunus Ali Rupom
 
Reactive Programming with JavaScript
Reactive Programming with JavaScriptReactive Programming with JavaScript
Reactive Programming with JavaScript
Codemotion
 
Typescript barcelona
Typescript barcelonaTypescript barcelona
Typescript barcelona
Christoffer Noring
 
Workshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & ReduxWorkshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & Redux
Visual Engineering
 

What's hot (20)

Protocol-Oriented MVVM (extended edition)
Protocol-Oriented MVVM (extended edition)Protocol-Oriented MVVM (extended edition)
Protocol-Oriented MVVM (extended edition)
 
Swift Delhi: Practical POP
Swift Delhi: Practical POPSwift Delhi: Practical POP
Swift Delhi: Practical POP
 
Anonymous functions in JavaScript
Anonymous functions in JavaScriptAnonymous functions in JavaScript
Anonymous functions in JavaScript
 
Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2Intro to Retrofit 2 and RxJava2
Intro to Retrofit 2 and RxJava2
 
Practical Protocols with Associated Types
Practical Protocols with Associated TypesPractical Protocols with Associated Types
Practical Protocols with Associated Types
 
Intro to Javascript
Intro to JavascriptIntro to Javascript
Intro to Javascript
 
Workshop 25: React Native - Components
Workshop 25: React Native - ComponentsWorkshop 25: React Native - Components
Workshop 25: React Native - Components
 
Protocol-Oriented MVVM
Protocol-Oriented MVVMProtocol-Oriented MVVM
Protocol-Oriented MVVM
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React Alicante
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 
Workshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScriptWorkshop 1: Good practices in JavaScript
Workshop 1: Good practices in JavaScript
 
Daggerate your code - Write your own annotation processor
Daggerate your code - Write your own annotation processorDaggerate your code - Write your own annotation processor
Daggerate your code - Write your own annotation processor
 
Intro to JavaScript
Intro to JavaScriptIntro to JavaScript
Intro to JavaScript
 
Taming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, MacoscopeTaming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, Macoscope
 
Workshop 5: JavaScript testing
Workshop 5: JavaScript testingWorkshop 5: JavaScript testing
Workshop 5: JavaScript testing
 
Scientific calcultor-Java
Scientific calcultor-JavaScientific calcultor-Java
Scientific calcultor-Java
 
Java final project of scientific calcultor
Java final project of scientific calcultorJava final project of scientific calcultor
Java final project of scientific calcultor
 
Reactive Programming with JavaScript
Reactive Programming with JavaScriptReactive Programming with JavaScript
Reactive Programming with JavaScript
 
Typescript barcelona
Typescript barcelonaTypescript barcelona
Typescript barcelona
 
Workshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & ReduxWorkshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & Redux
 

Similar to Kotlin Delegates in practice - Kotlin community conf

Scala cheatsheet
Scala cheatsheetScala cheatsheet
Scala cheatsheet
Arduino Aficionado
 
Oop lect3.pptx
Oop lect3.pptxOop lect3.pptx
Oop lect3.pptx
MrMudassir
 
6976.ppt
6976.ppt6976.ppt
Useful and Practical Functionalities in Realm
Useful and Practical Functionalities in RealmUseful and Practical Functionalities in Realm
Useful and Practical Functionalities in Realm
Yusuke Kita
 
K is for Kotlin
K is for KotlinK is for Kotlin
K is for Kotlin
TechMagic
 
Introduction to Swift
Introduction to SwiftIntroduction to Swift
Introduction to Swift
Matteo Battaglio
 
Kotlin for Android Developers - 3
Kotlin for Android Developers - 3Kotlin for Android Developers - 3
Kotlin for Android Developers - 3
Mohamed Nabil, MSc.
 
Why Spring <3 Kotlin
Why Spring <3 KotlinWhy Spring <3 Kotlin
Why Spring <3 Kotlin
VMware Tanzu
 
Ian 20150116 java script oop
Ian 20150116 java script oopIan 20150116 java script oop
Ian 20150116 java script oop
LearningTech
 
EmptyCollectionException-java -- - Represents the situation in which.docx
EmptyCollectionException-java --  - Represents the situation in which.docxEmptyCollectionException-java --  - Represents the situation in which.docx
EmptyCollectionException-java -- - Represents the situation in which.docx
BlakeSGMHemmingss
 
1. Suppose you want to implement an ADT in which you can insert valu.pdf
1. Suppose you want to implement an ADT in which you can insert valu.pdf1. Suppose you want to implement an ADT in which you can insert valu.pdf
1. Suppose you want to implement an ADT in which you can insert valu.pdf
forwardcom41
 
Pxb For Yapc2008
Pxb For Yapc2008Pxb For Yapc2008
Pxb For Yapc2008
maximgrp
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
Alena Holligan
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokusHamletDRC
 
For each task, submit your source java code file.(1) Objective Im.pdf
For each task, submit your source java code file.(1) Objective Im.pdfFor each task, submit your source java code file.(1) Objective Im.pdf
For each task, submit your source java code file.(1) Objective Im.pdf
dhavalbl38
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기
Arawn Park
 
In this lab, we will write an application to store a deck of cards i.pdf
In this lab, we will write an application to store a deck of cards i.pdfIn this lab, we will write an application to store a deck of cards i.pdf
In this lab, we will write an application to store a deck of cards i.pdf
contact41
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
ShaiAlmog1
 
[Deprecated] Integrating libSyntax into the compiler pipeline
[Deprecated] Integrating libSyntax into the compiler pipeline[Deprecated] Integrating libSyntax into the compiler pipeline
[Deprecated] Integrating libSyntax into the compiler pipeline
Yusuke Kita
 

Similar to Kotlin Delegates in practice - Kotlin community conf (20)

Scala cheatsheet
Scala cheatsheetScala cheatsheet
Scala cheatsheet
 
Oop lect3.pptx
Oop lect3.pptxOop lect3.pptx
Oop lect3.pptx
 
6976.ppt
6976.ppt6976.ppt
6976.ppt
 
Useful and Practical Functionalities in Realm
Useful and Practical Functionalities in RealmUseful and Practical Functionalities in Realm
Useful and Practical Functionalities in Realm
 
K is for Kotlin
K is for KotlinK is for Kotlin
K is for Kotlin
 
Introduction to Swift
Introduction to SwiftIntroduction to Swift
Introduction to Swift
 
Kotlin for Android Developers - 3
Kotlin for Android Developers - 3Kotlin for Android Developers - 3
Kotlin for Android Developers - 3
 
Why Spring <3 Kotlin
Why Spring <3 KotlinWhy Spring <3 Kotlin
Why Spring <3 Kotlin
 
Ian 20150116 java script oop
Ian 20150116 java script oopIan 20150116 java script oop
Ian 20150116 java script oop
 
EmptyCollectionException-java -- - Represents the situation in which.docx
EmptyCollectionException-java --  - Represents the situation in which.docxEmptyCollectionException-java --  - Represents the situation in which.docx
EmptyCollectionException-java -- - Represents the situation in which.docx
 
1. Suppose you want to implement an ADT in which you can insert valu.pdf
1. Suppose you want to implement an ADT in which you can insert valu.pdf1. Suppose you want to implement an ADT in which you can insert valu.pdf
1. Suppose you want to implement an ADT in which you can insert valu.pdf
 
Pxb For Yapc2008
Pxb For Yapc2008Pxb For Yapc2008
Pxb For Yapc2008
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
AST Transformations at JFokus
AST Transformations at JFokusAST Transformations at JFokus
AST Transformations at JFokus
 
Introduction to c ++ part -2
Introduction to c ++   part -2Introduction to c ++   part -2
Introduction to c ++ part -2
 
For each task, submit your source java code file.(1) Objective Im.pdf
For each task, submit your source java code file.(1) Objective Im.pdfFor each task, submit your source java code file.(1) Objective Im.pdf
For each task, submit your source java code file.(1) Objective Im.pdf
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기
 
In this lab, we will write an application to store a deck of cards i.pdf
In this lab, we will write an application to store a deck of cards i.pdfIn this lab, we will write an application to store a deck of cards i.pdf
In this lab, we will write an application to store a deck of cards i.pdf
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
 
[Deprecated] Integrating libSyntax into the compiler pipeline
[Deprecated] Integrating libSyntax into the compiler pipeline[Deprecated] Integrating libSyntax into the compiler pipeline
[Deprecated] Integrating libSyntax into the compiler pipeline
 

More from Fabio Collini

Using Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture projectUsing Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture project
Fabio Collini
 
Solid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon ItalySolid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon Italy
Fabio Collini
 
SOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
SOLID principles in practice: the Clean Architecture - Devfest Emila RomagnaSOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
SOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
Fabio Collini
 
SOLID principles in practice: the Clean Architecture
SOLID principles in practice: the Clean ArchitectureSOLID principles in practice: the Clean Architecture
SOLID principles in practice: the Clean Architecture
Fabio Collini
 
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFrom Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
Fabio Collini
 
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night TurinAsync code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Fabio Collini
 
Recap Google I/O 2018
Recap Google I/O 2018Recap Google I/O 2018
Recap Google I/O 2018
Fabio Collini
 
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italyFrom java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
Fabio Collini
 
From java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFrom java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+k
Fabio Collini
 
Testing Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UKTesting Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UK
Fabio Collini
 
Testing Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJavaTesting Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJava
Fabio Collini
 
Android Data Binding in action using MVVM pattern - droidconUK
Android Data Binding in action using MVVM pattern - droidconUKAndroid Data Binding in action using MVVM pattern - droidconUK
Android Data Binding in action using MVVM pattern - droidconUK
Fabio Collini
 
Data Binding in Action using MVVM pattern
Data Binding in Action using MVVM patternData Binding in Action using MVVM pattern
Data Binding in Action using MVVM pattern
Fabio Collini
 
Android Wear CodeLab - GDG Firenze
Android Wear CodeLab - GDG FirenzeAndroid Wear CodeLab - GDG Firenze
Android Wear CodeLab - GDG Firenze
Fabio Collini
 
Testable Android Apps using data binding and MVVM
Testable Android Apps using data binding and MVVMTestable Android Apps using data binding and MVVM
Testable Android Apps using data binding and MVVM
Fabio Collini
 
Introduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaIntroduction to Retrofit and RxJava
Introduction to Retrofit and RxJava
Fabio Collini
 
Testable Android Apps DroidCon Italy 2015
Testable Android Apps DroidCon Italy 2015Testable Android Apps DroidCon Italy 2015
Testable Android Apps DroidCon Italy 2015
Fabio Collini
 
Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014
Fabio Collini
 
Librerie su Android: come non reinventare la ruota @ whymca 2012
Librerie su Android: come non reinventare la ruota @ whymca 2012 Librerie su Android: come non reinventare la ruota @ whymca 2012
Librerie su Android: come non reinventare la ruota @ whymca 2012
Fabio Collini
 
Android Widget @ whymca 2011
Android Widget @ whymca 2011Android Widget @ whymca 2011
Android Widget @ whymca 2011
Fabio Collini
 

More from Fabio Collini (20)

Using Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture projectUsing Dagger in a Clean Architecture project
Using Dagger in a Clean Architecture project
 
Solid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon ItalySolid principles in practice the clean architecture - Droidcon Italy
Solid principles in practice the clean architecture - Droidcon Italy
 
SOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
SOLID principles in practice: the Clean Architecture - Devfest Emila RomagnaSOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
SOLID principles in practice: the Clean Architecture - Devfest Emila Romagna
 
SOLID principles in practice: the Clean Architecture
SOLID principles in practice: the Clean ArchitectureSOLID principles in practice: the Clean Architecture
SOLID principles in practice: the Clean Architecture
 
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf MilanFrom Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
From Java to Kotlin beyond alt+shift+cmd+k - Kotlin Community Conf Milan
 
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night TurinAsync code on kotlin: rx java or/and coroutines - Kotlin Night Turin
Async code on kotlin: rx java or/and coroutines - Kotlin Night Turin
 
Recap Google I/O 2018
Recap Google I/O 2018Recap Google I/O 2018
Recap Google I/O 2018
 
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italyFrom java to kotlin beyond alt+shift+cmd+k - Droidcon italy
From java to kotlin beyond alt+shift+cmd+k - Droidcon italy
 
From java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+kFrom java to kotlin beyond alt+shift+cmd+k
From java to kotlin beyond alt+shift+cmd+k
 
Testing Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UKTesting Android apps based on Dagger and RxJava Droidcon UK
Testing Android apps based on Dagger and RxJava Droidcon UK
 
Testing Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJavaTesting Android apps based on Dagger and RxJava
Testing Android apps based on Dagger and RxJava
 
Android Data Binding in action using MVVM pattern - droidconUK
Android Data Binding in action using MVVM pattern - droidconUKAndroid Data Binding in action using MVVM pattern - droidconUK
Android Data Binding in action using MVVM pattern - droidconUK
 
Data Binding in Action using MVVM pattern
Data Binding in Action using MVVM patternData Binding in Action using MVVM pattern
Data Binding in Action using MVVM pattern
 
Android Wear CodeLab - GDG Firenze
Android Wear CodeLab - GDG FirenzeAndroid Wear CodeLab - GDG Firenze
Android Wear CodeLab - GDG Firenze
 
Testable Android Apps using data binding and MVVM
Testable Android Apps using data binding and MVVMTestable Android Apps using data binding and MVVM
Testable Android Apps using data binding and MVVM
 
Introduction to Retrofit and RxJava
Introduction to Retrofit and RxJavaIntroduction to Retrofit and RxJava
Introduction to Retrofit and RxJava
 
Testable Android Apps DroidCon Italy 2015
Testable Android Apps DroidCon Italy 2015Testable Android Apps DroidCon Italy 2015
Testable Android Apps DroidCon Italy 2015
 
Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014Clean android code - Droidcon Italiy 2014
Clean android code - Droidcon Italiy 2014
 
Librerie su Android: come non reinventare la ruota @ whymca 2012
Librerie su Android: come non reinventare la ruota @ whymca 2012 Librerie su Android: come non reinventare la ruota @ whymca 2012
Librerie su Android: come non reinventare la ruota @ whymca 2012
 
Android Widget @ whymca 2011
Android Widget @ whymca 2011Android Widget @ whymca 2011
Android Widget @ whymca 2011
 

Recently uploaded

OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoamOpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
takuyayamamoto1800
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
Juraj Vysvader
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
Globus
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
Ortus Solutions, Corp
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus
 
2024 RoOUG Security model for the cloud.pptx
2024 RoOUG Security model for the cloud.pptx2024 RoOUG Security model for the cloud.pptx
2024 RoOUG Security model for the cloud.pptx
Georgi Kodinov
 
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar
 
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
informapgpstrackings
 
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdfDominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
AMB-Review
 
How Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptxHow Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptx
wottaspaceseo
 
Using IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New ZealandUsing IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New Zealand
IES VE
 
Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...
Globus
 
Visitor Management System in India- Vizman.app
Visitor Management System in India- Vizman.appVisitor Management System in India- Vizman.app
Visitor Management System in India- Vizman.app
NaapbooksPrivateLimi
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
Globus
 
Advanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should KnowAdvanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should Know
Peter Caitens
 
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus
 
De mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FMEDe mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FME
Jelle | Nordend
 
Cyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdf
Cyanic lab
 
Accelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with PlatformlessAccelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with Platformless
WSO2
 
Corporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMSCorporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMS
Tendenci - The Open Source AMS (Association Management Software)
 

Recently uploaded (20)

OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoamOpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
OpenFOAM solver for Helmholtz equation, helmholtzFoam / helmholtzBubbleFoam
 
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
In 2015, I used to write extensions for Joomla, WordPress, phpBB3, etc and I ...
 
First Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User EndpointsFirst Steps with Globus Compute Multi-User Endpoints
First Steps with Globus Compute Multi-User Endpoints
 
Into the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdfInto the Box 2024 - Keynote Day 2 Slides.pdf
Into the Box 2024 - Keynote Day 2 Slides.pdf
 
Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024Globus Compute wth IRI Workflows - GlobusWorld 2024
Globus Compute wth IRI Workflows - GlobusWorld 2024
 
2024 RoOUG Security model for the cloud.pptx
2024 RoOUG Security model for the cloud.pptx2024 RoOUG Security model for the cloud.pptx
2024 RoOUG Security model for the cloud.pptx
 
SOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBrokerSOCRadar Research Team: Latest Activities of IntelBroker
SOCRadar Research Team: Latest Activities of IntelBroker
 
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
Field Employee Tracking System| MiTrack App| Best Employee Tracking Solution|...
 
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdfDominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
Dominate Social Media with TubeTrivia AI’s Addictive Quiz Videos.pdf
 
How Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptxHow Recreation Management Software Can Streamline Your Operations.pptx
How Recreation Management Software Can Streamline Your Operations.pptx
 
Using IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New ZealandUsing IESVE for Room Loads Analysis - Australia & New Zealand
Using IESVE for Room Loads Analysis - Australia & New Zealand
 
Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...Developing Distributed High-performance Computing Capabilities of an Open Sci...
Developing Distributed High-performance Computing Capabilities of an Open Sci...
 
Visitor Management System in India- Vizman.app
Visitor Management System in India- Vizman.appVisitor Management System in India- Vizman.app
Visitor Management System in India- Vizman.app
 
Enhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdfEnhancing Research Orchestration Capabilities at ORNL.pdf
Enhancing Research Orchestration Capabilities at ORNL.pdf
 
Advanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should KnowAdvanced Flow Concepts Every Developer Should Know
Advanced Flow Concepts Every Developer Should Know
 
Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024Globus Connect Server Deep Dive - GlobusWorld 2024
Globus Connect Server Deep Dive - GlobusWorld 2024
 
De mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FMEDe mooiste recreatieve routes ontdekken met RouteYou en FME
De mooiste recreatieve routes ontdekken met RouteYou en FME
 
Cyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdfCyaniclab : Software Development Agency Portfolio.pdf
Cyaniclab : Software Development Agency Portfolio.pdf
 
Accelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with PlatformlessAccelerate Enterprise Software Engineering with Platformless
Accelerate Enterprise Software Engineering with Platformless
 
Corporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMSCorporate Management | Session 3 of 3 | Tendenci AMS
Corporate Management | Session 3 of 3 | Tendenci AMS
 

Kotlin Delegates in practice - Kotlin community conf

  • 1. Kotlin delegates in practice Fabio Collini @fabioCollini
  • 2. “” “The ratio of time spent reading (code) versus writing is well over 10 to 1 (therefore) making it easy to read makes it easier to write Robert C. Martin
  • 3. “” “The Principle of Least Astonishment states that the result of performing some operation should be obvious, consistent, and predictable, based upon the name of the operation and other clues https://wiki.c2.com/?PrincipleOfLeastAstonishment
  • 4. Kotlin code is readable Data classes Extension functions Sealed classes Coroutines Delegates …
  • 6. public class MyEquivalentJavaClass { private final String property = slowMethod(); public String getProperty() { return property; }5 }6 class MyClass { val property = slowMethod() }1
  • 7. public class MyEquivalentJavaClass { private String property = slowMethod(); public String getProperty() { return property; } public void setProperty(String var1) { this.property = var1; }5 }6 class MyClass { var property = slowMethod() }1
  • 8. public class MyEquivalentJavaClass { private String property = slowMethod(); }6 class MyClass { private var property = slowMethod() }1
  • 9. public class MyEquivalentJavaClass { public String getProperty() { return slowMethod(); }5 }6 class MyClass { val property get() = slowMethod() }1
  • 10. class MyClass { val property = slowMethod() }1 fun main() { val obj = MyClass() println(obj.property)A println(obj.property)B }2
  • 11. class MyClass { val property = slowMethod() }1 fun main() { println("starting") val obj = MyClass() println("obj created") println(obj.property)A println(obj.property)B println("end") }2 starting slowMethod invoked obj created end
  • 12. class MyClass { val property get() = slowMethod() }1 fun main() { println("starting") val obj = MyClass() println("obj created") println(obj.property)A println(obj.property)B println("end") }2 starting obj created slowMethod invoked slowMethod invoked end
  • 13. class MyClass { val property by lazy { slowMethod() }3 }1 fun main() { println("starting") val obj = MyClass() println("obj created") println(obj.property)A println(obj.property)B println("end") }2 starting obj created slowMethod invoked end
  • 14. class MyClass { val property by lazy { slowMethod() }3 }1
  • 15. by
  • 16. public class MyEquivalentJavaClass { private SimpleLazy lazy = new SimpleLazy(::slowMethod); public String getProperty() { return lazy.getValue(); } }
  • 17. internal object UNINITIALIZED_VALUE class SimpleLazy<T>(private val initializer: () -> T) { private var value: Any? = UNINITIALIZED_VALUE fun getValue(): T { if (value == UNINITIALIZED_VALUE) { value = initializer() }4 return value as T }3 }2
  • 18. /** * Specifies how a Lazy instance synchronizes initialization among multiple threads. */ public enum class LazyThreadSafetyMode { /** * Locks are used to ensure that only a single thread can initialize the Lazy instance. */ SYNCHRONIZED, /** * Initializer function can be called several times on concurrent access to * uninitialized Lazy instance value, * but only the first returned value will be used as the value of Lazy instance. */ PUBLICATION, /** * No locks are used to synchronize an access to the Lazy instance value; * if the instance is accessed from multiple threads, its behavior is undefined. * * This mode should not be used unless the Lazy instance is guaranteed never to * be initialized from more than one thread. */ NONE } Default value
  • 19. class MyClass { val notAGoodIdea by lazy { 2 + 2 }3 }1
  • 20. class MyClass { suspend val property by lazy { slowMethod() }1 }2 suspend fun slowMethod() = withContext(IO) { //... }3 Modifier 'suspend' is not applicable to 'member property with delegate' Suspend function 'slowMethod' should be called only from a coroutine or another suspend function
  • 21.
  • 22. class MyFragment : Fragment() { private val appName by lazy { getString(R.string.app_name) }1 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) println("Starting $appName...") }2 }3 Lazy
  • 23. class MyFragment : Fragment() { private lateinit var appName: String override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) appName = getString(R.string.app_name) println("Starting $appName...") }4 }5 lateinit
  • 24. class MyFragment : Fragment() { private lateinit var appName: String override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) appName = getString(R.string.app_name) println("Starting $appName...") }4 }5 lateinit class MyFragment : Fragment() { private val appName by lazy { getString(R.string.app_name) }1 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) println("Starting $appName...") }2 }3 Lazy
  • 25. class MyFragment : Fragment() { private lateinit var appName: String private lateinit var title: String private lateinit var summary: String private lateinit var text: String override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) appName = getString(R.string.app_name) title = getString(R.string.title) summary = getString(R.string.summary) text = "$appNamen$titlen$summary" println(text) }4 }5 lateinit class MyFragment2 : Fragment() { private val appName by lazy { getString(R.string.app_name) } private val title by lazy { getString(R.string.title) } private val summary by lazy { getString(R.string.summary) } private val text by lazy { "$appNamen$titlen$summary" } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) println(text) }2 }3 Lazy
  • 27. operator fun getValue(thisRef: Any, property: KProperty<*>): T
  • 28. /** * Base interface that can be used for implementing property delegates of read-only properties. *1 * This is provided only for convenience; you don't have to extend this interface * as long as your property delegate has methods with the same signatures. *2 * @param R the type of object which owns the delegated property. * @param T the type of the property value. */ interface ReadOnlyProperty<in R, out T> { /** * Returns the value of the property for the given object. * @param thisRef the object for which the value is requested. * @param property the metadata for the property. * @return the property value. */ operator fun getValue(thisRef: R, property: KProperty<*>): T }3
  • 29. class LogDelegate<T>(initialValue: T) : ReadOnlyProperty<Any, T> { private var value: T = initialValue override fun getValue(thisRef: Any, property: KProperty<*>): T { println("get invoked on $thisRef.${property.name}") return value }1 }2
  • 30. class LogDelegate<T>(initialValue: T) : ReadOnlyProperty<Any, T> { private var value: T = initialValue override fun getValue(thisRef: Any, property: KProperty<*>): T { println("get invoked on $thisRef.${property.name}") return value }1 }2 class MyClass { val property by LogDelegate("ABC") }3
  • 31. class LogDelegate<T>(initialValue: T) : ReadOnlyProperty<Any, T> { private var value: T = initialValue override fun getValue(thisRef: Any, property: KProperty<*>): T { println("get invoked on $thisRef.${property.name}") return value }1 }2 class MyClass { val property by LogDelegate("ABC") }3 fun main() { val obj = MyClass() println(obj.property) }4 get invoked on MyClass@87aac27.property ABC
  • 32. /** * Base interface that can be used for implementing property delegates of read-write properties. * * This is provided only for convenience; you don't have to extend this interface * as long as your property delegate has methods with the same signatures. * * @param R the type of object which owns the delegated property. * @param T the type of the property value. */ interface ReadWriteProperty<in R, T> { /** * Returns the value of the property for the given object. * @param thisRef the object for which the value is requested. * @param property the metadata for the property. * @return the property value. */ operator fun getValue(thisRef: R, property: KProperty<*>): T /** * Sets the value of the property for the given object. * @param thisRef the object for which the value is requested. * @param property the metadata for the property. * @param value the value to set. */ operator fun setValue(thisRef: R, property: KProperty<*>, value: T) }
  • 33. class LogDelegate<T>(initialValue: T) : ReadWriteProperty<Any, T> { private var value: T = initialValue override fun getValue(thisRef: Any, property: KProperty<*>): T { println("get invoked on $thisRef.${property.name}") return value }1 override fun setValue(thisRef: Any, property: KProperty<*>, value: T) { println("set invoked on $thisRef.${property.name} with value $value") this.value = value }5 }2 class MyClass { var property by LogDelegate("ABC") }3 fun main() { val obj = MyClass() println(obj.property) obj.property = "DEF" println(obj.property) }4 get invoked on MyClass@e9e54c2.property ABC set invoked on MyClass@e9e54c2.property with value DEF get invoked on MyClass@e9e54c2.property DEF
  • 35. class TokenHolder(private val prefs: SharedPreferences) { val token: String? get() = prefs.getString(TOKEN, null) val count: Int get() = prefs.getInt(COUNT, 0) fun saveToken(newToken: String) { prefs.edit { putString(TOKEN, newToken) putInt(COUNT, count + 1) }1 }2 companion object { private const val TOKEN = "token" private const val COUNT = "count" }3 }4
  • 36. class TokenHolder(private val prefs: SharedPreferences) { val token: String? get() = prefs.getString(TOKEN, null) val count: Int get() = prefs.getInt(COUNT, 0) fun saveToken(newToken: String) { prefs.edit { putString(TOKEN, newToken) putInt(COUNT, count + 1) }1 }2 companion object { private const val TOKEN = "token" private const val COUNT = "count" }3 }4
  • 37. class TokenHolder(private val prefs: SharedPreferences) { val token: String? get() = prefs.getString(TOKEN, null) val count: Int get() = prefs.getInt(COUNT, 0) fun saveToken(newToken: String) { prefs.edit { putString(TOKEN, newToken) putInt(COUNT, count + 1) }1 }2 companion object { private const val TOKEN = "token" private const val COUNT = "count" }3 }4
  • 38. class TokenHolder(private val prefs: SharedPreferences) { val token: String? get() = prefs.getString(TOKEN, null) val count: Int get() = prefs.getInt(COUNT, 0) fun saveToken(newToken: String) { prefs.edit { putString(TOKEN, newToken) putInt(COUNT, count + 1) }1 }2 companion object { private const val TOKEN = "token" private const val COUNT = "count" }3 }4
  • 39. fun main() { val tokenHolder = TokenHolder(sharedPreferences()) tokenHolder.saveToken("ABC") println("${tokenHolder.token} - ${tokenHolder.count}") tokenHolder.saveToken("DEF") println("${tokenHolder.token} - ${tokenHolder.count}") } ABC - 1 DEF - 2
  • 40. fun SharedPreferences.int() = object : ReadWriteProperty<Any, Int> { override fun getValue(thisRef: Any, property: KProperty<*>) = getInt(property.name, 0) override fun setValue(thisRef: Any, property: KProperty<*>, value: Int) = edit { putInt(property.name, value) } }1
  • 41. fun SharedPreferences.int() = object : ReadWriteProperty<Any, Int> { override fun getValue(thisRef: Any, property: KProperty<*>) = getInt(property.name, 0) override fun setValue(thisRef: Any, property: KProperty<*>, value: Int) = edit { putInt(property.name, value) } }1
  • 42. fun SharedPreferences.int(key: String, defaultValue: Int = 0) = object : ReadWriteProperty<Any, Int> { override fun getValue(thisRef: Any, property: KProperty<*>) = getInt(key, defaultValue) override fun setValue(thisRef: Any, property: KProperty<*>, value: Int) = edit { putInt(key, value) } }1
  • 43. fun SharedPreferences.int(key: String, defaultValue: Int = 0) = object : ReadWriteProperty<Any, Int> { override fun getValue(thisRef: Any, property: KProperty<*>) = getInt(key, defaultValue) override fun setValue(thisRef: Any, property: KProperty<*>, value: Int) = edit { putInt(key, value) } }1 fun SharedPreferences.string(key: String, defaultValue: String? = null) = object : ReadWriteProperty<Any, String?> { override fun getValue(thisRef: Any, property: KProperty<*>) = getString(key, defaultValue) override fun setValue(thisRef: Any, property: KProperty<*>, value: String?) = edit { putString(key, value) } }2
  • 44. class TokenHolder(private val prefs: SharedPreferences) { val token: String? get() = prefs.getString(TOKEN,0null)1 val count: Int get() = prefs.getInt(COUNT, 0) fun saveToken(newToken: String) { prefs.edit { putString(TOKEN, newToken) putInt(COUNT, count + 1) }1 }2 companion object { private const val TOKEN = "token" private const val COUNT = "count" }3 }4
  • 45. class TokenHolder(private val prefs: SharedPreferences) { var token by prefs.string(TOKEN)1 private3set val count: Int get() = prefs.getInt(COUNT, 0) fun saveToken(newToken: String) { prefs.edit { putString(TOKEN, newToken) putInt(COUNT, count + 1) }1 }2 companion object { private const val TOKEN = "token" private const val COUNT = "count" }3 }4
  • 46. class TokenHolder(private val prefs: SharedPreferences) { var token by prefs.string(TOKEN)1 private set val count: Int get() = prefs.getInt(COUNT, 0) fun saveToken(newToken: String) { token = newToken prefs.edit { putInt(COUNT, count + 1) }1 }2 companion object { private const val TOKEN = "token" private const val COUNT = "count" }3 }4
  • 47. class TokenHolder(private val prefs: SharedPreferences) { var token by prefs.string("token")1 private set val count: Int get() = prefs.getInt(COUNT, 0)2 fun saveToken(newToken: String) { token = newToken prefs.edit { putInt(COUNT, count + 1) }1 }2 companion object { private const val COUNT = "count" }3 }4
  • 48. class TokenHolder(private val prefs: SharedPreferences) { var token by prefs.string("token") private set var count by prefs.int(COUNT)2 private set fun saveToken(newToken: String) { token = newToken prefs.edit { putInt(COUNT, count + 1) }1 }2 companion object { private const val COUNT = "count" }3 }4
  • 49. class TokenHolder(private val prefs: SharedPreferences) { var token by prefs.string("token") private set var count by prefs.int(COUNT)2 private set fun saveToken(newToken: String) { token = newToken count++ }2 companion object { private const val COUNT = "count" }3 }4
  • 50. class TokenHolder(private val prefs: SharedPreferences) { var token by prefs.string("token") private set var count by prefs.int("count")2 private set fun saveToken(newToken: String) { token = newToken count++ }2 }4
  • 51. class TokenHolder(prefs: SharedPreferences) { var token by prefs.string("token") private set var count by prefs.int("count") private set fun saveToken(newToken: String) { token = newToken count++ }2 }4 prefs.edit { putInt("count", prefs.getInt("count", 0) + 1) }
  • 52. class DemoFragment : Fragment() { private val component by lazy { //... } private val viewModel by viewModelProvider { component.myViewModel() } //... } https://proandroiddev.com/kotlin-delegates-in-android-development-part-2-2c15c11ff438
  • 53. class DemoFragment : Fragment() { private var param1: Int by argument() private var param2: String by argument() companion object { fun newInstance(param1: Int, param2: String): DemoFragment = DemoFragment().apply { this.param1 = param1 this.param2 = param2 } } } https://proandroiddev.com/kotlin-delegates-in-android-1ab0a715762d
  • 55. object AnalyticsLib { fun trackEvent(event: Map<String, Any?>) { println(event) }1 }2 fun main() { val event = mapOf( "name" to "myEvent", "value" to 123 )3 AnalyticsLib.trackEvent(event) }4
  • 56. fun main() { val event = mapOf( "name" to "myEvent", "value" to 123 )3 AnalyticsLib.trackEvent(event) }4
  • 57. const val NAME = "name" const val VALUE = "value" fun main() { val event = mapOf( NAME to "myEvent", VALUE to 123 )3 AnalyticsLib.trackEvent(event) }4
  • 58. const val NAME = "name" const val VALUE = "value" fun main() { val event = mapOf( NAME to "myEvent", VALUE to "this should be an Int :(" )3 AnalyticsLib.trackEvent(event) }4
  • 59. class MyEvent { val map: MutableMap<String, Any?> = mutableMapOf() var name: String by map var value: Int by map }1 fun main() { val event = MyEvent().apply { name = "myEvent" value = 123 }2 AnalyticsLib.trackEvent(event.map) }3
  • 60. data class MyEvent(val name: String, val value: Int) { val map = mapOf( "name" to name, "value" to value ) }1 fun main() { val event = MyEvent( name = "myEvent", value = 123 )2 AnalyticsLib.trackEvent(event.map) }3
  • 61. object AbTestLib { fun readValues() = mapOf<String, Any?>( "featureEnabled" to true, "delay" to 1000 )1 }2
  • 62. object AbTestLib { fun readValues() = mapOf<String, Any?>( "featureEnabled" to true, "delay" to 1000 )1 }2 fun main() { val values = AbTestLib.readValues() println(values["featureEnabled"] as Boolean) println(values["delay"] as Int) }3 true 1000
  • 63. data class AbValues(private val map: Map<String, Any?>) { val featureEnabled: Boolean by map val delay: Int by map }1 fun main() { val values = AbValues(AbTestLib.readValues()) println(values.featureEnabled) println(values.delay) }2
  • 64. data class AbValues(private val map: Map<String, Any?>) { val featureEnabled: Boolean by map val delay: Int by map }1 fun main() { val values = AbValues( mapOf<String, Any?>( "featureEnabled" to "true", "delay" to "1000" ) ) println(values.featureEnabled) println(values.delay) }2 Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Boolean
  • 65. class User { var name: String by Delegates.observable("<no name>") { prop, old, new -> println("$old -> $new") } } class User { var name: String by Delegates.vetoable("<no name>") { prop, old, new -> new.startsWith("f") } } ObservableVetoable
  • 66. class MyClass { var myIntVar: Int by notNull() fun onCreate() { myIntVar = calculateValue() } } notNull
  • 68. Inheritance open class Class1 { fun doSomething() = 123 }1 class Class2 : Class1()
  • 69. Composition class Class1 { fun doSomething() = 123 } class Class2 { private val wrapped = Class1() fun doSomething() = wrapped.doSomething() }
  • 70. Delegation interface Interface1 { fun doSomething(): Int }4 class Class1 : Interface1 { override fun doSomething() = 123 }5 class Class2(private val wrapped: Class1 = Class1()) : Interface1 by wrapped
  • 71. Delegation interface Interface1 { fun doSomething(): Int }4 class Class1 : Interface1 { override fun doSomething() = 123 }5 class Class2 : Interface1 by Class1() 11
  • 72. Delegation interface Interface1 { fun doSomething(): Int }4 class Class1 : Interface1 { override fun doSomething() = 123 }5 class Class2 : Interface1 by Class1() fun main() { val obj = Class2() println(obj.doSomething()) }m Composition class Class1 { fun doSomething() = 123 }2 class Class2 { private val wrapped = Class1() fun doSomething() = wrapped.doSomething() }3 Inheritance open class Class1 { fun doSomething() = 123 }1 class Class2 : Class1()
  • 73. interface HasMargin { val marginBottom: Int val marginTop: Int val marginLeft: Int val marginRight: Int }1 class Style( val backgroundColor: Int, override val marginBottom: Int, override val marginTop: Int, override val marginLeft: Int, override val marginRight: Int ) : HasMargin class View(style: Style) : HasMargin by style { fun draw() { //... } }
  • 74. [ { "type": "student", "name": "studentName", "surname": "studentSurname", "age": 20, "university": "universityName" }, { //... } ] data class PersonJson( val type: String, val name: String, val surname: String, val age: Int, val university: String?, val company: String? )
  • 75. abstract class Person( val name: String, val surname: String, val age: Int ) class Student( name: String, surname: String, age: Int, val university: String ) : Person(name, surname, age) class Worker( name: String, surname: String, age: Int, val company: String ) : Person(name, surname, age)
  • 76. fun main() { val json: List<PersonJson> = listOf(/* ... */) val people = json.map { if (it.type == "student") Student( it.name, it.surname, it.age, it.university!! ) else Worker( it.name, it.surname, it.age, it.company!! ) } println(people.joinToString { "${it.name} ${it.surname}" }) }
  • 77. abstract class Person( val_name: String, val_surname: String, val_age: Int ) class Student( name: String, surname: String, age: Int, val university: String ) : Person(name, surname, age)_ class Worker( name: String, surname: String, age: Int, val company: String ) : Person(name, surname, age)_
  • 78. abstract class Person { abstract val_name: String abstract val_surname: String abstract val_age: Int }1 data class Student( override val name: String, override val surname: String, override val age: Int, val university: String ) : Person()_ data class Worker( override val name: String, override val surname: String, override val age: Int, val company: String ) : Person()_
  • 79. interface Person { val name: String val surname: String val age: Int }1 data class Student( override val name: String, override val surname: String, override val age: Int, val university: String ) : Person data class Worker( override val name: String, override val surname: String, override val age: Int, val company: String ) : Person
  • 80. interface Person { val name: String val surname: String val age: Int }1
  • 81. interface Person { val name: String val surname: String val age: Int }1 data class PersonData( override val name: String, override val surname: String, override val age: Int ) : Person
  • 82. data class Student( override val name: String, override val surname: String, override val age: Int, val university: String ) : Person data class Worker( override val name: String, override val surname: String, override val age: Int, val company: String ) : Person
  • 83. data class Student( override val name: String, override val surname: String, override val age: Int, val university: String ) : Person data class Worker( override val name: String, override val surname: String, override val age: Int, val company: String ) : Person data class Student( val data: PersonData, val university: String ) : Person by data data class Worker( val data: PersonData, val company: String ) : Person by data
  • 84. fun main() { val json: List<PersonJson> = listOf(/* ... */) val people = json.map { val data = PersonData( it.name, it.surname, it.age ) if (it.type == "student") Student(data, it.university!!) else Worker(data, it.company!!) } println(people.joinToString { "${it.name} ${it.surname}" }) }
  • 85. interface Person { val name: String val surname: String val age: Int } data class Student( override val name: String, override val surname: String, override val age: Int, val university: String ) : Person data class Worker( override val name: String, override val surname: String, override val age: Int, val company: String ) : Person fun main() { val json: List<PersonJson> = listOf(/* ... */) val people = json.map { if (it.type == "student") Student( it.name, it.surname, it.age, it.university!! ) else Worker( it.name, it.surname, it.age, it.company!! ) } println(people.joinToString { "${it.name} ${it.surname}" }) } interface Person { val name: String val surname: String val age: Int } data class PersonData( override val name: String, override val surname: String, override val age: Int ) : Person data class Student( val data: PersonData, val university: String ) : Person by data data class Worker( val data: PersonData, val company: String ) : Person by data fun main() { val json: List<PersonJson> = listOf(/* ... */) val people = json.map { val data = PersonData( it.name, it.surname, it.age ) if (it.type == "student") Student(data, it.university!!) else Worker(data, it.company!!) } println(people.joinToString { "${it.name} ${it.surname}" }) } DelegationInheritance
  • 86. interface Person { val name: String val surname: String val age: Int val address: String val city: String val zipCode: String val nation: String val telephoneNumber1: String val telephoneNumber2: String val telephoneNumber3: String } data class Student( override val name: String, override val surname: String, override val age: Int, val university: String, override val address: String, override val city: String, override val zipCode: String, override val nation: String, override val telephoneNumber1: String, override val telephoneNumber2: String, override val telephoneNumber3: String ) : Person data class Worker( override val name: String, override val surname: String, override val age: Int, val company: String, override val address: String, override val city: String, override val zipCode: String, override val nation: String, override val telephoneNumber1: String, override val telephoneNumber2: String, override val telephoneNumber3: String ) : Person data class Unemployed( override val name: String, override val surname: String, override val age: Int, override val address: String, override val city: String, override val zipCode: String, override val nation: String, override val telephoneNumber1: String, override val telephoneNumber2: String, override val telephoneNumber3: String ) : Person fun main() { val json: List<PersonJson> = listOf(/* ... */) val people = json.map { if (it.type == "student") Student( it.name, it.surname, it.age, it.university!!, it.address, it.city, it.zipCode, it.nation, it.telephoneNumber1, it.telephoneNumber2, it.telephoneNumber3 ) else if (it.type == "worker") Worker( it.name, it.surname, it.age, it.company!!, it.address, it.city, it.zipCode, it.nation, it.telephoneNumber1, it.telephoneNumber2, it.telephoneNumber3 ) else Unemployed( it.name, it.surname, it.age, it.address, it.city, it.zipCode, it.nation, it.telephoneNumber1, it.telephoneNumber2, it.telephoneNumber3 ) } println(people.joinToString { "${it.name} ${it.surname}" }) } interface Person { val name: String val surname: String val age: Int val address: String val city: String val zipCode: String val nation: String val telephoneNumber1: String val telephoneNumber2: String val telephoneNumber3: String } data class PersonData( override val name: String, override val surname: String, override val age: Int, override val address: String, override val city: String, override val zipCode: String, override val nation: String, override val telephoneNumber1: String, override val telephoneNumber2: String, override val telephoneNumber3: String ) : Person data class Student( val data: PersonData, val university: String ) : Person by data data class Worker( val data: PersonData, val company: String ) : Person by data data class Unemployed( val data: PersonData ) : Person by data fun main() { val json: List<PersonJson> = listOf(/* ... */) val people = json.map { val data = PersonData( it.name, it.surname, it.age, it.address, it.city, it.zipCode, it.nation, it.telephoneNumber1, it.telephoneNumber2, it.telephoneNumber3 ) if (it.type == "student") Student(data, it.university!!) else if (it.type == "worker") Worker(data, it.company!!) else Unemployed(data) } println(people.joinToString { "${it.name} ${it.surname}" }) } DelegationInheritance
  • 87. Wrappingup “” “The ratio of time spent reading (code) versus writing is well over 10 to 1 (therefore) making it easy to read makes it easier to write Robert C. Martin
  • 88. Wrappingup “” “The Principle of Least Astonishment states that the result of performing some operation should be obvious, consistent, and predictable, based upon the name of the operation and other clues https://wiki.c2.com/?PrincipleOfLeastAstonishment
  • 89. Wrappingup Delegates can be useful to simplify code but there are pros and cons!
  • 90. Links&contacts Simpler Kotlin class hierarchies using class delegation proandroiddev.com/simpler-kotlin-class-hierarchies-using-class-delegation-35464106fed5 Kotlin delegates in Android development — Part 1 medium.com/hackernoon/kotlin-delegates-in-android-development-part-1-50346cf4aed7 Kotlin delegates in Android development — Part 2 proandroiddev.com/kotlin-delegates-in-android-development-part-2-2c15c11ff438 @fabioCollini linkedin.com/in/fabiocollini github.com/fabioCollini medium.com/@fabioCollini