This presentation is part of a workshop series.
In this section you will learn about Java interop, synthetic and delegated properties, custom setters and getters, lateinit, nullable and non-null properties, and optional invocation
License:
This presentation is licensed under the Creative Commons, No Derivatives, Version 3.0 US: https://creativecommons.org/licenses/by-nd/3.0/us/legalcode
3. Kotlin Properties
PROPERTIES
interface Factory<T: Any> {
var mock: T?
}
class Provider<T: Any>(init: () -> T): Factory<T> {
override var mock: T? = null
val instance: T by lazy(init)
}
provider.mock = mock(...)
y/kotlin-workbook
● Properties replace java fields
● Declared in primary constructor or at the top of a class
● Declaration is like variables inside a function
● Can be declared inside interfaces
4. Kotlin Properties
PROPERTIES
interface Factory<T: Any> {
var mock: T?
}
class Provider<T: Any>(init: () -> T): Factory<T> {
override var mock: T? = null
val instance: T by lazy(init)
private set
}
provider.mock = mock(...)
y/kotlin-workbook
● Properties replace java fields
● Declaration is like variables inside a type
● Can be declared inside interfaces
● Properties compile into:
○ A field + getter for val
○ A field + getter & setter for var
○ The field is private
○ Getter has same visibility
○ Setter defaults to same visibility
5. private final String string;
String getString() // Java getter
val string: String // Kotlin val
private CharSequence text;
CharSequence getText() // Java getter
void setText(CharSequence sss) // Java setter
var text: CharSequence // Kotlin var
private Boolean isMarried;
Boolean isMarried() // Java getter
void setMarried(Boolean married) // Java setter
var isMarried: Boolean // Kotlin var
Java Synthetic
Properties
PROPERTIES
y/kotlin-workbook
6. Kotlin Properties
PROPERTIES
interface Factory<T: Any> {
var mock: T?
}
class Provider<T: Any>(init: () -> T): Factory<T> {
override var mock: T? = null
@get:JvmName("it")
val instance: T by lazy(init)
private set
}
provider.mock = mock(...)
y/kotlin-workbook
● Properties replace java fields
● Declaration is like variables inside a type
● Can be declared inside interfaces
● Properties compile into several members
● Use qualifiers to annotate a part of a property
7. Annotation Qualifiers
PROPERTIES
y/kotlin-workbook
Qualifier @Foo applies to
@file:Foo Entire .kt file
@param:Foo Parameter of a single-param fun
@receiver:Foo Receiver of a fun with receiver
Below are exclusive or most relevant to properties
@property:Foo The property ¯_(ツ)_/¯
@field:Foo Field of a property
@get:Foo Getter of a property
@set:Foo Setter of a property
@setparam:Foo The parameter of the setter of a property
@delegate:Foo The delegate of a property
8. // Suppress unused warnings in the file
@file:Suppress("unused")
// Get a string through context
fun @receiver:StringRes Int.getString() = …
class Example(
// annotate Java field
@field:DrawableRes val foo: Int,
// annotate Java getter
@get:VisibleForTesting val bar: Boolean,
// annotate Java constructor parameter
@param:Mock val quux)
Annotation Qualifiers
PROPERTIES
y/kotlin-workbook
9. ● Delegate the implementation of a property
● Has to implement getValue() for val
● Additionally setValue() for var
Property Delegates
PROPERTIES
y/kotlin-workbook
10. Property Delegates
PROPERTIES
interface Delegate<T> {
operator fun getValue(
thisRef: Any?,
property: KProperty<T>): T
operator fun setValue(
thisRef: Any?,
property: KProperty<T>,
value: T)
}
y/kotlin-workbook
● Delegate the implementation of a property
● Has to implement getValue() for val
● Additionally setValue() for var
11. class C {
var p: T by MyDelegate()
}
// Compiles down to:
class C {
private val p$delegate = MyDelegate()
var p: T
get() = p$delegate.getValue(this, this::p)
set(v: T) = p$delegate.setValue(this, this::p, v)
}
Property Delegates
PROPERTIES
y/kotlin-workbook
12. class Foo {
val foo: String by lazy { "moo" }
val bar: Int by lazy { 5 }
}
Property Delegates
PROPERTIES
y/kotlin-workbook
13. open class BackedByMap {
protected val _map = mutableMapOf<String, Any?>()
}
class Foo : BackedByMap() {
var foo: String? by _map
var bar: Int? by _map
}
Property Delegates
Magic
PROPERTIES
y/kotlin-workbook
14. open class BackedByMap {
protected val _map = mutableMapOf<String, Any?>()
}
class Foo : BackedByMap() {
var foo: String? by _map
var bar: Int? by _map
}
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
Property Delegates
Magic
PROPERTIES
y/kotlin-workbook
15. Property Delegates
Magic
PROPERTIES
open class BackedByMap {
protected val _map = mutableMapOf<String, Any?>()
}
class Foo : BackedByMap() {
var foo: String? by _map
var bar: Int? by _map
}
val f = Foo()
f.foo = "moo"
f.bar = 5
y/kotlin-workbook
16. Property Delegates
Magic
PROPERTIES
open class BackedByMap {
protected val _map = mutableMapOf<String, Any?>()
val map get() = _map.toMap()
}
class Foo : BackedByMap() {
var foo: String? by _map
var bar: Int? by _map
}
val f = Foo()
println(f.map) // {}
f.foo = "moo"
f.bar = 5
println(f.map) // {foo=moo, bar=5}
f.foo = null
println(f.map) // {foo=null, bar=5}
f.bar = null
println(f.map) // {foo=null, bar=null}
y/kotlin-workbook
17. Property Delegates
Magic
PROPERTIES
open class BackedByMap {
protected val _map = mutableMapOf<String, Any?>()
val map get() = _map.filterValues { it != null }
}
class Foo : BackedByMap() {
var foo: String? by _map
var bar: Int? by _map
}
val f = Foo()
println(f.map) // {}
f.foo = "moo"
f.bar = 5
println(f.map) // {foo=moo, bar=5}
f.foo = null
println(f.map) // {bar=5}
f.bar = null
println(f.map) // {}
y/kotlin-workbook
18. ● Kind of like lazy
● Limited to var
● No additional code
● Compiler will not check and may crash at runtime
● Only makes sense for non-null properties
lateinit
PROPERTIES
y/kotlin-workbook
19. ● Every type has a nullable version
○ Any vs Any?Nullability
PROPERTIES
y/kotlin-workbook
20. Nullability
PROPERTIES
val any: Any = Any()
val maybe: Any? = null
fun show(maybe: Any?) = print(maybe)
fun reallyShow(any: Any) = print(any)
show(maybe)
show(any)
reallyShow(any)
reallyShow(maybe) // compiler error
maybe?.let(::reallyShow) // Coming Soon™
y/kotlin-workbook
● Every type has a nullable version - Any?
● Can supply non-nullable argument to a nullable
parameter
○ Vice-versa is a compiler error
21. Nullability
PROPERTIES
val maybe: Any? = null
maybe.hashCode() // Compiler error
maybe?.hashCode() // OK
maybe?.hashCode().compareTo(42) // Compiler error
maybe?.hashCode()?.compareTo(42) // OK
if (maybe != null) {
maybe.hashCode() // Compiler knows value is nonnull
}y/kotlin-workbook
● Every type has a nullable version - Any?
● Can supply non-nullable argument to a nullable
parameter
● Safe invocation
22. Nullability
PROPERTIES
val maybe: Any? = null
fun Any?.hashCode() = this?.hashCode() ?: 0
maybe.hashCode() // OK
maybe.hashCode().compareTo(42) // OK
y/kotlin-workbook
● Every type has a nullable version - Any?
● Can supply non-nullable argument to a nullable
parameter
● Safe invocation
● You can extend nullable types
23. Nullability
PROPERTIES
val any: Any = Any()
val maybe: Any? = null
fun Any?.hashCode() = this?.hashCode() ?: 0
maybe.hashCode() // OK
any.hashCode() // OK
maybe.hashCode().compareTo(42) // OK
y/kotlin-workbook
● Every type has a nullable version - Any?
● Can supply non-nullable argument to a nullable
parameter
● Safe invocation
● You can extend nullable types
Talk about non-nullable annotations and their nullable counter-parts
We’ll talk more about nullability itself later
Additional overloads don’t matter
isFoo() and setFoo()
Talk about custom implementations for get() and set()
If you do not access the generated field via the keyword field the compiler will not generate it
Properties like that are generally referred to as virtual or synthetic
Most common delegate from std-lib - lazy
In case we don’t come up with better example mention that this is a bad use case and can be replaced with assignment
ALMOST END OF SLIDES - NEXT SLIDE IS LAST - Q&A STARTS