Slide 1

Slide 1 text

Understanding Kotlin Type System

Slide 2

Slide 2 text

@brunoaybarg Bruno125 Bruno Aybar Senior Android Developer @ Avantica https://brunoaybar.com/talks/kotlin-type-system

Slide 3

Slide 3 text

- Jetbrains “Kotlin is a (…) statically typed programming language”

Slide 4

Slide 4 text

String name = ""; Class

Slide 5

Slide 5 text

String name = ""; int age = 10; Class Primitive
 Type

Slide 6

Slide 6 text

String name = ""; int age = 10; List list = ... Class Primitive
 Type Interface

Slide 7

Slide 7 text

Classes ≠ Types you’ll understand how by the end!

Slide 8

Slide 8 text

Kotlin build-in types Logical Boolean Integral Byte Char Int Long Floating Point Float Double Structured Array String Function types And…? Any Nothing Unit

Slide 9

Slide 9 text

User-Defined Types Classes Interfaces Enums

Slide 10

Slide 10 text

User-Defined Types Classes Interfaces Enums Function
 Types Nullable
 operator Generics New types when 
 combined with

Slide 11

Slide 11 text

Kotlin Type Hierarchy … but let’s look at Java’s hierarchy first

Slide 12

Slide 12 text

Integer String MyClass Object MySubClass Number

Slide 13

Slide 13 text

Int String MyClass Any MySubClass Number Nothing

Slide 14

Slide 14 text

Int String MyClass Any MySubClass Number Nothing

Slide 15

Slide 15 text

Int String MyClass Any MySubClass Number Nothing

Slide 16

Slide 16 text

Int String MyClass Any MySubClass Number Nothing

Slide 17

Slide 17 text

Any Object = ? Int String MyClass MySubClass Number Nothing

Slide 18

Slide 18 text

fun test(param: Any) { } public final static test(Ljava/lang/Object;)V @Lorg/jetbrains/annotations/NotNull;() LDC "param" INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull LINENUMBER 3 L1 RETURN L2 LOCALVARIABLE param Ljava/lang/Object; L0 L2 0 bytecode

Slide 19

Slide 19 text

Object test = null; Java: Kotlin: val test: Any = null ✘

Slide 20

Slide 20 text

Any Any? Subtyping by Nullability

Slide 21

Slide 21 text

Int String MyClass Any MySubClass Number Nothing Any?

Slide 22

Slide 22 text

Int String MyClass Any MySubClass Number Nothing Any? Int? String? MyClass? MySubClass? Number? Nothing?

Slide 23

Slide 23 text

Int String MyClass Any MySubClass Number Nothing Any? Int? String? MyClass? MySubClass? Number? Nothing?

Slide 24

Slide 24 text

When we define a class class MyClass We automatically have 2 types available val a: MyClass val b: MyClass?

Slide 25

Slide 25 text

User-Defined Types Classes Interfaces Enums Function
 Types Generics Nullable
 operator New types when 
 combined with

Slide 26

Slide 26 text

Any Any? Subtyping by Nullability

Slide 27

Slide 27 text

When we define a class class MyClass We automatically have 2 types available val a: MyClass val b: MyClass? … while coding

Slide 28

Slide 28 text

When we define a class class MyClass After compilation, the “non nullable” concept no longer
 exists

Slide 29

Slide 29 text

fun test(param: Any) { } public final static test(Ljava/lang/Object;)V @Lorg/jetbrains/annotations/NotNull;() LDC "param" INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull LINENUMBER 3 L1 RETURN L2 LOCALVARIABLE param Ljava/lang/Object; L0 L2 0 bytecode

Slide 30

Slide 30 text

fun test(param: Any?) { } public final static test(Ljava/lang/Object;)V @Lorg/jetbrains/annotations/Nullable;() // invisible, parameter 0 L0 LINENUMBER 3 L0 RETURN L1 LOCALVARIABLE param Ljava/lang/Object; L0 L1 0 bytecode

Slide 31

Slide 31 text

Any Object = ? Int String MyClass MySubClass Number Nothing

Slide 32

Slide 32 text

Any Object = ? Int String MyClass MySubClass Number Nothing

Slide 33

Slide 33 text

Nothing

Slide 34

Slide 34 text

Int String MyClass Any MySubClass Number Nothing

Slide 35

Slide 35 text

Int String MyClass Any MySubClass Number Nothing Nothing never returns a value It is mainly used for control flow

Slide 36

Slide 36 text

data class Data(val name: String?, val lastName: String?)

Slide 37

Slide 37 text

data class Data(val name: String?, val lastName: String?) fun hasValidData(data: Data?): Boolean { val name = data?.name ?: return false val lastName = data.lastName ?: return false return name.isNotBlank() && lastName.isNotBlank() }

Slide 38

Slide 38 text

data class Data(val name: String?, val lastName: String?) fun hasValidData(data: Data?): Boolean { val name = data?.name ?: return false val lastName = data.lastName ?: return false return name.isNotBlank() && lastName.isNotBlank() } val name = data?.name ?: return false

Slide 39

Slide 39 text

val name = data?.name ?: return false Which is the inferred type?

Slide 40

Slide 40 text

val name: String = data?.name ?: return false

Slide 41

Slide 41 text

Why is it possible to assign 
 return 
 to a variable? val name: String = data?.name ?: return false

Slide 42

Slide 42 text

In Kotlin, mostly everything
 is an expression

Slide 43

Slide 43 text

val name = when(number) -> { 1 -> "one" 2 -> “two" ... } Inferred type?

Slide 44

Slide 44 text

val message = if(number % 2) "This is an even number" else "This is an odd number" Inferred type?

Slide 45

Slide 45 text

val function = fun(param: String) { ... } Inferred type?

Slide 46

Slide 46 text

Why is it possible to assign 
 return 
 to a variable? val name: String = data?.name ?: return false

Slide 47

Slide 47 text

val name: String = data?.name ?: return false returns Nothing

Slide 48

Slide 48 text

val name: String = data?.name ?: return false String Nothing

Slide 49

Slide 49 text

Int String MyClass Any MySubClass Number Nothing

Slide 50

Slide 50 text

val name: String = data?.name ?: return false String Nothing Liskov Substitution
 Principle subtype

Slide 51

Slide 51 text

Liskov Substitution
 Principle if S is a subtype of T, 
 then objects of type T may be replaced with objects of type S 
 without altering any of the desirable properties of that program

Slide 52

Slide 52 text

Liskov Substitution
 Principle Fruit Apple Orange val fruit: Fruit = Fruit()

Slide 53

Slide 53 text

Liskov Substitution
 Principle Fruit Apple Orange val fruit: Fruit = Apple()

Slide 54

Slide 54 text

Liskov Substitution
 Principle Fruit Apple Orange val fruit: Fruit = Apple() fun peel(fruit: Fruit) { } peel(Fruit())

Slide 55

Slide 55 text

Liskov Substitution
 Principle Fruit Apple Orange val fruit: Fruit = Apple() fun peel(fruit: Fruit) { } peel(Orange())

Slide 56

Slide 56 text

val name: String = data?.name ?: return false String Nothing

Slide 57

Slide 57 text

data class Data(val name: String?, val lastName: String?) fun hasValidData(data: Data?): Boolean { val lastName = data.lastName ?: return false return name.isNotBlank() && lastName.isNotBlank() } val name: String = data?.name ?: return false

Slide 58

Slide 58 text

data class Data(val name: String?, val lastName: String?) fun hasValidData(data: Data?): Boolean { val name: String = return false val lastName = data.lastName ?: return false return name.isNotBlank() && lastName.isNotBlank() } Perfectly possible
 (but doesn’t make sense)

Slide 59

Slide 59 text

Why is it possible to assign 
 return 
 to a variable? val name: String = data?.name ?: return false

Slide 60

Slide 60 text

Because Nothing is a subtype of everything val name: String = data?.name ?: return false

Slide 61

Slide 61 text

Throw returns Nothing too

Slide 62

Slide 62 text

fun hasValidData(data: Data?): Boolean { val name = data?.name ?: throw RuntimeException() val lastName = data.lastName ?: return false return name.isNotBlank() && lastName.isNotBlank() } Throw returns Nothing too

Slide 63

Slide 63 text

public inline fun TODO(): Nothing = throw NotImplementedError() Kotlin STD example fun test(): Boolean { TODO() return true } WARNING: 
 Unreachable code

Slide 64

Slide 64 text

The compiler knows that after Nothing is returned, 
 the execution flows stops

Slide 65

Slide 65 text

val name: String = data?.name ?: return false so this will actually never be assigned ... because the function ends with the return statement

Slide 66

Slide 66 text

fun forever(): Nothing { while(true) { } } Or you can define your own fun test(): Boolean { forever() return true } WARNING: 
 Unreachable code

Slide 67

Slide 67 text

fun forever(): Nothing { while(false) { } } What if we change the condition? The compiler knows that!

Slide 68

Slide 68 text

fun forever(): Nothing { while(false) { } } What if we change the condition? A ‘return' expression required in a function with a body (‘{…}’)

Slide 69

Slide 69 text

fun forever(): Nothing { while(false) { } return ????? } What if we return something? It is impossible to 
 create an instance of
 Nothing

Slide 70

Slide 70 text

fun forever(): Nothing? { return null while(true) { } } Nothing? ≠ Nothing fun test(): Boolean { forever() return true } NO WARNING: 
 Reachable code

Slide 71

Slide 71 text

fun print(value: Any?) = println(when(value) { is String -> "text: $value" is Int -> "integer: $value" else -> "unexpected value: $value" }) fun main() { print(“Message!”) }

Slide 72

Slide 72 text

fun print(value: Any?) = println(when(value) { is String -> "text: $value" is Int -> "integer: $value" else -> "unexpected value: $value" }) fun main() { print(“Message!”) } text: Message!

Slide 73

Slide 73 text

fun print(value: Any?) = println(when(value) { is String -> "text: $value" is Int -> "integer: $value" else -> "unexpected value: $value" }) fun main() { print(10) }

Slide 74

Slide 74 text

fun print(value: Any?) = println(when(value) { is String -> "text: $value" is Int -> "integer: $value" else -> "unexpected value: $value" }) fun main() { print(10) } integer: 10

Slide 75

Slide 75 text

fun print(value: Any?) = println(when(value) { is String -> "text: $value" is Int -> "integer: $value" else -> "unexpected value: $value" }) fun main() { print(false) }

Slide 76

Slide 76 text

fun print(value: Any?) = println(when(value) { is String -> "text: $value" is Int -> "integer: $value" else -> "unexpected value: $value" }) fun main() { print(false) } Unexpected value: false

Slide 77

Slide 77 text

fun print(value: Any?) = println(when(value) { is String -> "text: $value" is Int -> "integer: $value" else -> "unexpected value: $value" }) fun main() { print(null) }

Slide 78

Slide 78 text

fun print(value: Any?) = println(when(value) { is String -> "text: $value" is Int -> "integer: $value" else -> "unexpected value: $value" }) fun main() { print(null) } Unexpected value: null

Slide 79

Slide 79 text

fun print(value: Any?) = println(when(value) { is String -> "text: $value" is Int -> "integer: $value" is null -> "null value!" else -> "unexpected value: $value" }) fun main() { print(null) }

Slide 80

Slide 80 text

fun print(value: Any?) = println(when(value) { is String -> "text: $value" is Int -> "integer: $value" is null -> "null value!" else -> "unexpected value: $value" }) fun main() { print(null) } Type Expected

Slide 81

Slide 81 text

fun print(value: Any?) = println(when(value) { is String -> "text: $value" is Int -> "integer: $value" is ???? -> "null value!" else -> "unexpected value: $value" }) fun main() { print(null) }

Slide 82

Slide 82 text

fun print(value: Any?) = println(when(value) { is String -> "text: $value" is Int -> "integer: $value" is Nothing? -> "null value!" else -> "unexpected value: $value" }) fun main() { print(null) }

Slide 83

Slide 83 text

fun print(value: Any?) = println(when(value) { is String -> "text: $value" is Int -> "integer: $value” is Nothing? -> "null value!" else -> "unexpected value: $value" }) fun main() { print(null) } null value!

Slide 84

Slide 84 text

User-Defined Types Classes Interfaces Enums Function
 Types Generics Nullable
 operator New types when 
 combined with ✔

Slide 85

Slide 85 text

User-Defined Types Classes Interfaces Enums Function
 Types Nullable
 operator Generics New types when 
 combined with ✔

Slide 86

Slide 86 text

For every class that supports generics class Response It’s not a type by itself

Slide 87

Slide 87 text

For every class that supports generics class Response But these are val a: Response val b: Response? ...

Slide 88

Slide 88 text

For every class that supports generics class Response But these are val a: Response val b: Response? ... … while coding

Slide 89

Slide 89 text

For every class that supports generics class Response After compilation, the generic type is erased Type Erasure

Slide 90

Slide 90 text

class Response { fun evaluate() { print("Type: ${T::class.java}") } }

Slide 91

Slide 91 text

class Response { fun evaluate() { print("Type: ${T::class.java}") } } Cannot use ’T' as a reified parameter.
 Use class instead Type is no 
 longer available!

Slide 92

Slide 92 text

class Response { fun evaluate() { print("Type: ${T::class.java}") } } Cannot use ’T' as a reified parameter.
 Use class instead No work around

Slide 93

Slide 93 text

class Response { } fun evaluate() { print("Type: ${T::class.java}") }

Slide 94

Slide 94 text

fun evaluate() { print("Type: ${T::class.java}") }

Slide 95

Slide 95 text

fun evaluate(r: Response) { print("Type: ${T::class.java}") }

Slide 96

Slide 96 text

fun evaluate(r: Response) { print("Type: ${T::class.java}") } Cannot use ’T' as a reified parameter.
 Use class instead

Slide 97

Slide 97 text

inline fun evaluate(r: Response) { print("Type: ${T::class.java}") }

Slide 98

Slide 98 text

inline fun evaluate(r: Response) { print("Type: ${T::class.java}") } No error! Because value is inlined (homework)

Slide 99

Slide 99 text

Type Hierarchy for Generics

Slide 100

Slide 100 text

Fruit Apple Orange class Box Box Box Box

Slide 101

Slide 101 text

Fruit Apple Orange class Box Box Box Box ✘ ✘

Slide 102

Slide 102 text

Fruit Apple Orange class Box Box Box Box

Slide 103

Slide 103 text

Covariance and Contravariance

Slide 104

Slide 104 text

Fruit Apple Orange class Box Box Box Box

Slide 105

Slide 105 text

Fruit Apple Orange Box Box Box class Box

Slide 106

Slide 106 text

Fruit Apple Orange class Box Box Box Box

Slide 107

Slide 107 text

Fruit Apple Orange class Box Box Box Box

Slide 108

Slide 108 text

User-Defined Types Classes Interfaces Enums Function
 Types Nullable
 operator Generics New types when 
 combined with ✔ ✔

Slide 109

Slide 109 text

User-Defined Types Classes Interfaces Enums Generics Nullable
 operator Function
 Types New types when 
 combined with ✔ ✔ no time left :(

Slide 110

Slide 110 text

Kotlin build-in types Logical Boolean Integral Byte Char Int Long Floating Point Float Double Structured Array String Function types And…? Any Nothing ✔ ✔ Unit

Slide 111

Slide 111 text

Int String MyClass Any MySubClass Number Nothing Unit

Slide 112

Slide 112 text

Int String MyClass MySubClass Number Nothing Any Unit

Slide 113

Slide 113 text

fun test() { } fun test(): Unit { } public object Unit { override fun toString() = "kotlin.Unit" }

Slide 114

Slide 114 text

fun test() { } fun test(): Unit { } These are not pure functions,
 they only have side effects

Slide 115

Slide 115 text

Pure function 1. Given an input, always emits same output 2. No side effects
 
 3. 100% Unit testable

Slide 116

Slide 116 text

fun sum(a: Int, b: Int): Int { return a + b } Pure ✔

Slide 117

Slide 117 text

fun sum(a: Int, b: Int): Int { return a + b + random() } Not pure ✘

Slide 118

Slide 118 text

Not pure ✘ fun sum(a: Int, b: Int): Int { print("Side effect!") return a + b }

Slide 119

Slide 119 text

Not pure ✘ fun sum(a: Int, b: Int): Int { updateDatabase(a) return a + b }

Slide 120

Slide 120 text

Study material - Exploring the Kotlin Type Hierarchy from Top to Bottom
 https://www.youtube.com/watch?v=juFkdMv4B9s 
 - Programmer dictionary: Class vs Type vs Object
 https://blog.kotlin-academy.com/programmer-dictionary-class-vs-type-vs- object-e6d1f74d1e2e - An Illustrated Guide to Covariance and Contravariance
 in Kotlin https://typealias.com/guides/illustrated-guide-covariance- contravariance/
 - Getting Real with Kotlin's Reified Type Parameters
 https://typealias.com/guides/getting-real-with-reified-type-parameters/

Slide 121

Slide 121 text

@brunoaybarg Bruno125 Bruno Aybar Senior Android Developer @ Avantica Thanks! https://brunoaybar.com/talks/kotlin-type-system