Slide 1

Slide 1 text

What’s new in Kotlin? Svetlana Isakova @sveta_isakova Beijing

Slide 2

Slide 2 text

Kotlin developers 0 750 1500 2250 3000 2016 2017 2018 156K 700K 2.2M

Slide 3

Slide 3 text

Timeline … … 2017 Official on Android 2010 Project started 2016 Kotlin 1.0 2018 Kotlin 1.3

Slide 4

Slide 4 text

Kotlin evolution Kotlin 1.2 Kotlin 1.0 Kotlin 1.1 Kotlin 1.3 Coroutines (experimental) Coroutines get stable! Multi-platform projects can target Kotlin/Native (experimental) Multi-platform projects (experimental) Kotlin/Native (experimental) Kotlin gets stable!

Slide 5

Slide 5 text

Agenda • Kotlin evolution • “Experimental” features

Slide 6

Slide 6 text

Agenda: experimental features • Inline Classes • Contracts • Channels • Flows • Multiplatform Projects

Slide 7

Slide 7 text

Principles of Pragmatic Evolution Language design is cast in stone, but this stone is reasonably soft, and with some effort we can reshape it later. Kotlin Design Team * The real sculpture made by José Manuel Castro López

Slide 8

Slide 8 text

Principles of Pragmatic Evolution • keeping the language modern • comfortable updates • feedback loop

Slide 9

Slide 9 text

KEEPing the language modern https://github.com/Kotlin/KEEP KEEP = Kotlin Evolution and Enhancement Process contains language proposals and the corresponding discussions

Slide 10

Slide 10 text

Comfortable updates • Deprecation warnings in advance • Automatic migration

Slide 11

Slide 11 text

Feedback loop with the community • Kotlin the community • Kotlin team listens to the community • The community members influence the Kotlin evolution

Slide 12

Slide 12 text

Contributors from all over the world …

Slide 13

Slide 13 text

Experimental features

Slide 14

Slide 14 text

Experimental features The goal: to let new features be tried by early adopters as soon as possible

Slide 15

Slide 15 text

Experimental Language Features • can be changed in the future • you need to explicitly opt in at the call site to use experimental features compileTestKotlin { kotlinOptions { freeCompilerArgs += "-Xinline-classes" } }

Slide 16

Slide 16 text

Experimental API for Libraries • can be publicly released as a part of the library • may break at any moment

Slide 17

Slide 17 text

@ShinyNewAPI class Foo { ... } Experimental API @Experimental annotation class ShinyNewAPI You can mark your new class or function as experimental

Slide 18

Slide 18 text

Using experimental API @UseExperimental(ShinyNewAPI::class) fun doSomethingImportant() { val foo = Foo() ... }

Slide 19

Slide 19 text

• feedback loop for new features and API Experimental: Summary

Slide 20

Slide 20 text

Inline classes

Slide 21

Slide 21 text

Inline classes • can wrap values without additional overhead • currently an experimental feature

Slide 22

Slide 22 text

Duration API • KEEP: Duration and Time Measurement API • status: experimental in Kotlin 1.3.50 • uses inline classes

Slide 23

Slide 23 text

Refining API: trying primitive args fun greetAfterTimeout(millis: Long) greetAfterTimeout(2) // meaning 2 seconds?

Slide 24

Slide 24 text

Refining API: trying primitive args fun greetAfterTimeout(millis: Long) greetAfterTimeout(2) // meaning 2 seconds? Too easy to make a mistake

Slide 25

Slide 25 text

Refining API: trying overloads fun greetAfterTimeoutMillis(millis: Long) fun greetAfterTimeoutSeconds(seconds: Long) greetAfterTimeoutSeconds(2)

Slide 26

Slide 26 text

Refining API: trying overloads fun greetAfterTimeoutMillis(millis: Long) fun greetAfterTimeoutSeconds(seconds: Long) greetAfterTimeoutSeconds(2) Too verbose

Slide 27

Slide 27 text

Refining API: trying class fun greetAfterTimeout(duration: Duration) greetAfterTimeout(Duration(millis = 2000)) class Duration(val millis: Long)

Slide 28

Slide 28 text

Refining API: trying class fun greetAfterTimeout(duration: Duration) greetAfterTimeout(Duration(millis = 2000)) Extra object is allocated class Duration(val millis: Long)

Slide 29

Slide 29 text

Inline classes to the rescue inline class Duration(val value: Long) fun greetAfterTimeout(duration: Duration) fun greetAfterTimeout_(duration: Long) Under the hood:

Slide 30

Slide 30 text

Inline classes to the rescue inline class Duration(val value: Long) fun greetAfterTimeout(duration: Duration) fun greetAfterTimeout_(duration: Long) Under the hood: No extra object is allocated! ✓

Slide 31

Slide 31 text

Inline classes constraints inline class Duration(val value: Long) fun greetAfterTimeout(duration: Duration) inline class can define only one val property

Slide 32

Slide 32 text

Creating Duration fun greetAfterTimeout(duration: Duration) greetAfterTimeout(2.seconds) ✓ Explicit units in the code val Int.seconds get() = toDuration(DurationUnit.SECONDS)

Slide 33

Slide 33 text

Inline classes: summary • KEEP: inline classes • help to improve API and avoid extra allocations • you can go and try it out

Slide 34

Slide 34 text

Contracts

Slide 35

Slide 35 text

Changes in standard library fun String?.isNullOrEmpty(): Boolean { return this == null || this.length == 0 }

Slide 36

Slide 36 text

Changes in standard library fun String?.isNullOrEmpty(): Boolean { return this == null || this.length == 0 } fun String?.isNullOrEmpty(): Boolean { contract { returns(false) implies (this@isNullOrEmpty != null) } return this == null || this.length == 0 }

Slide 37

Slide 37 text

Changes in standard library fun String?.isNullOrEmpty(): Boolean { contract { returns(false) implies (this@isNullOrEmpty != null) } return this == null || this.length == 0 } fun String?.isNullOrEmpty(): Boolean { return this == null || this.length == 0 }

Slide 38

Slide 38 text

val s: String? = "" if (!s.isNullOrEmpty()) { s.first() } We know something about isNullOrEmpty, which the compiler doesn’t

Slide 39

Slide 39 text

val s: String? = "" if (!s.isNullOrEmpty()) { s.first() } Compiler error: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String? We know something about isNullOrEmpty, which the compiler doesn’t

Slide 40

Slide 40 text

val s: String? = "" if (!s.isNullOrEmpty()) { s.first() } Compiler error: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String? We know something about isNullOrEmpty, which the compiler doesn’t if (s != null && s.isNotEmpty()) { s.first() } ✓

Slide 41

Slide 41 text

We know something about run, that the compiler doesn’t val answer: Int run { answer = 42 } println(answer)

Slide 42

Slide 42 text

We know something about run, that the compiler doesn’t val answer: Int run { answer = 42 } println(answer) Compiler error: Captured values initialization is forbidden due to possible reassignment

Slide 43

Slide 43 text

Kotlin Contracts …allow to share extra information about code semantics with the compiler

Slide 44

Slide 44 text

fun String?.isNullOrEmpty(): Boolean { contract { returns(false) implies (this@isNullOrEmpty != null) } return this == null || this.length == 0 } Contract: if the function returns false, the receiver is not-null

Slide 45

Slide 45 text

fun String?.isNullOrEmpty(): Boolean { contract { returns(false) implies (this@isNullOrEmpty != null) } return this == null || this.length == 0 } Contract: if the function returns false, the receiver is not-null val s: String? = "" if (!s.isNullOrEmpty()) { s.first() } ✓

Slide 46

Slide 46 text

inline fun run(block: () -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block() } Contract: block lambda will be always called once

Slide 47

Slide 47 text

inline fun run(block: () -> R): R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block() } Contract: block lambda will be always called once val answer: Int run { answer = 42 } ✓

Slide 48

Slide 48 text

Why can’t compiler just implicitly infer such information?

Slide 49

Slide 49 text

Why can’t compiler just implicitly infer such information? Because then such implicitly inferred information: - can be implicitly changed - can accidentally break code depending on it

Slide 50

Slide 50 text

Why can’t compiler just implicitly infer such information? Because then such implicitly inferred information: - can be implicitly changed - can accidentally break code depending on it

Slide 51

Slide 51 text

Contract = explicit statement about function behaviour Why can’t compiler just implicitly infer such information? Because then such implicitly inferred information: - can be implicitly changed - can accidentally break code depending on it

Slide 52

Slide 52 text

Kotlin Contract extra information by developer & compiler uses this information for code analysis experimental

Slide 53

Slide 53 text

Kotlin Contract extra information by developer & compiler uses this information for code analysis & checking that the information is correct at compile time or runtime to be supported

Slide 54

Slide 54 text

• handy functions (run, isEmptyOrNull) are even more useful • contract DSL will change • more use-cases in the future • you can define contracts for your own functions Contracts: Summary

Slide 55

Slide 55 text

Channels

Slide 56

Slide 56 text

Channels used for synchronization communication between coroutines

Slide 57

Slide 57 text

“Share by communicating” Shared
 Mutable State Share by Communicating Synchronization
 Primitives Communication Primitives

Slide 58

Slide 58 text

channel coroutine #2 coroutine #1 send receive Channel

Slide 59

Slide 59 text

channel consumer #1 producer #1 send receive producer #2 producer #N consumer #M ... ... Producer-consumer problem

Slide 60

Slide 60 text

Send & Receive “views” for the same channel interface SendChannel { suspend fun send(element: E) fun close() } interface ReceiveChannel { suspend fun receive(): E } interface Channel : SendChannel, ReceiveChannel

Slide 61

Slide 61 text

Send & Receive “views” for the same channel interface SendChannel { suspend fun send(element: E) fun close() } interface ReceiveChannel { suspend fun receive(): E } interface Channel : SendChannel, ReceiveChannel

Slide 62

Slide 62 text

consumer #1 producer #1 send tasks receive tasks consumer #2 Producer-consumer problem

Slide 63

Slide 63 text

Producer-consumer solution: producer val channel = Channel() async { channel.send(Task("task1")) channel.send(Task("task2")) channel.close() } producer

Slide 64

Slide 64 text

Producer-consumer solution: consumers val channel = Channel() ... async { worker(channel) } async { worker(channel) } consumer #1 suspend fun worker(channel: Channel) { val task = channel.receive() processTask(task) } consumer #2

Slide 65

Slide 65 text

Producer-consumer solution val channel = Channel()

Slide 66

Slide 66 text

Producer-consumer solution val channel = Channel() val task = channel.receive() processTask(task)

Slide 67

Slide 67 text

Producer-consumer solution val channel = Channel() val task = channel.receive() processTask(task) receive

Slide 68

Slide 68 text

receive Producer-consumer solution val channel = Channel() waiting for “send” val task = channel.receive() processTask(task)

Slide 69

Slide 69 text

Producer-consumer solution val channel = Channel() receive waiting for “send” val task = channel.receive() processTask(task) channel.send(task1) channel.send(task2) channel.close()

Slide 70

Slide 70 text

send(task1) Producer-consumer solution val channel = Channel() receive waiting for “send” val task = channel.receive() processTask(task) channel.send(task1) channel.send(task2) channel.close()

Slide 71

Slide 71 text

send(task1) Producer-consumer solution val channel = Channel() receive Rendezvous! waiting for “send” val task = channel.receive() processTask(task) channel.send(task1) channel.send(task2) channel.close()

Slide 72

Slide 72 text

Producer-consumer solution val channel = Channel() send(task1) receive Rendezvous! val task = channel.receive() processTask(task) channel.send(task1) channel.send(task2) channel.close()

Slide 73

Slide 73 text

Producer-consumer solution val channel = Channel() val task = channel.receive() processTask(task) processing task1 channel.send(task1) channel.send(task2) channel.close()

Slide 74

Slide 74 text

send(task2) Producer-consumer solution val channel = Channel() processing task1 val task = channel.receive() processTask(task) channel.send(task1) channel.send(task2) channel.close()

Slide 75

Slide 75 text

send(task2) Producer-consumer solution val channel = Channel() waiting for “receive” val task = channel.receive() processTask(task) processing task1 channel.send(task1) channel.send(task2) channel.close()

Slide 76

Slide 76 text

send(task2) Producer-consumer solution val channel = Channel() receive val task = channel.receive() processTask(task) val task = channel.receive() processTask(task) processing task1 channel.send(task1) channel.send(task2) channel.close()

Slide 77

Slide 77 text

send(task2) Producer-consumer solution val channel = Channel() receive Rendezvous! val task = channel.receive() processTask(task) val task = channel.receive() processTask(task) processing task1 channel.send(task1) channel.send(task2) channel.close()

Slide 78

Slide 78 text

Producer-consumer solution val channel = Channel() processing task2 val task = channel.receive() processTask(task) val task = channel.receive() processTask(task) processing task1 channel.send(task1) channel.send(task2) channel.close()

Slide 79

Slide 79 text

consumer #1 producer #1 send tasks receive tasks consumer #2 Producer-consumer solution: many tasks val channel = Channel()

Slide 80

Slide 80 text

Producer-consumer solution: many tasks val channel = Channel() async { for (i in 1..N) { channel.send(Task("task$i")) } channel.close() } producer

Slide 81

Slide 81 text

Producer-consumer solution: many tasks val channel = Channel() ... async { worker(channel) } async { worker(channel) } consumer #1 consumer #2 suspend fun worker(channel: Channel) { for (task in channel) { processTask(task) } } calls receive while iterating

Slide 82

Slide 82 text

send receive ... unbuffered buffered send receive “rendezvous” send receive Types of Channels conflated send

Slide 83

Slide 83 text

send receive ... unbuffered buffered send receive “rendezvous” send receive Types of Channels conflated

Slide 84

Slide 84 text

send receive ... unbuffered buffered send receive “rendezvous” send receive Types of Channels conflated send

Slide 85

Slide 85 text

send receive ... unbuffered buffered send receive “rendezvous” send receive Types of Channels conflated

Slide 86

Slide 86 text

send receive ... unbuffered buffered send receive “rendezvous” send receive Types of Channels conflated send

Slide 87

Slide 87 text

send receive ... unbuffered buffered send receive “rendezvous” send receive Types of Channels conflated

Slide 88

Slide 88 text

send receive ... unbuffered buffered send receive “rendezvous” send receive Types of Channels conflated receive

Slide 89

Slide 89 text

Channels: summary • used for communication between different coroutines • stable part of the kotlinx.coroutines library

Slide 90

Slide 90 text

Flows

Slide 91

Slide 91 text

Flow • suspend-based reactive stream flow { emit(value) } .map { transform(it) } .filter { condition(it) } .catch { exception -> log(exception) } .collect { process(it) }

Slide 92

Slide 92 text

Integration with RxJava Use extension functions: • flow.asPublisher() • publisher.asFlow()

Slide 93

Slide 93 text

Backpressure • Backpressure happens automatically thanks to suspension mechanism

Slide 94

Slide 94 text

Flows: summary • bring reactive streams to coroutines library • currently in an experimental state • will get stable soon

Slide 95

Slide 95 text

Multi-platform Projects

Slide 96

Slide 96 text

fun Char.isUpperCase(): Boolean = java.lang.Character.isUpperCase(this) Before: expect / actual in standard library

Slide 97

Slide 97 text

expect fun Char.isUpperCase(): Boolean public actual fun Char.isUpperCase(): Boolean = java.lang.Character.isUpperCase(this) Now: fun Char.isUpperCase(): Boolean = java.lang.Character.isUpperCase(this) Before: expect / actual in standard library

Slide 98

Slide 98 text

expect fun Char.isUpperCase(): Boolean public actual fun Char.isUpperCase(): Boolean = java.lang.Character.isUpperCase(this) Now: fun Char.isUpperCase(): Boolean = java.lang.Character.isUpperCase(this) Before: expect / actual in standard library

Slide 99

Slide 99 text

Multi-platform projects Browser Kotlin/JS Android Kotlin/JVM iOS Kotlin/Native Server Kotlin/JVM common code

Slide 100

Slide 100 text

Sharing common code • Sharing business logic • Keeping UI platform-dependent • The shared part might vary

Slide 101

Slide 101 text

Common code • you define expect declarations in the common code and use them • you provide different actual implementations for different platforms

Slide 102

Slide 102 text

Time measurement example expect fun measureTime(action: () -> Unit): Duration Expected platform-specific API: Expected API can be used in the common code: measureTime { // operation }

Slide 103

Slide 103 text

Platform-specific Implementations expect fun measureTime(action: () -> Unit): Duration actual fun measureTime(action: () -> Unit): Duration { // implementation using System.nanoTime() } actual fun measureTime(action: () -> Unit): Duration { // implementation using window.performance.now() } actual fun measureTime(action: () -> Unit): Duration { // implementation using std::chrono::high_resolution_clock } Kotlin/JVM Kotlin/JS Kotlin/Native

Slide 104

Slide 104 text

Common code • can use the standard library • can define expect declarations and use them • can use other multi-platform libraries

Slide 105

Slide 105 text

Multi-platform libraries • Standard library • Ktor HTTP client • kotlinx.serialization • kotlinx.coroutines • … and more

Slide 106

Slide 106 text

Many apps already in production Going Native: How I used Kotlin Native to Port 6 years of Android Game Code to iOS in 6 months Shipping a Mobile Multiplatform Project on iOS & Android Your Multiplatform Kaptain has Arrived: iOS release is powered by Kotlin Multiplatform

Slide 107

Slide 107 text

Multi-platform projects: summary • a modern approach to multi-platform development • you can easily tune what parts you want to be shared • you can go and try it out

Slide 108

Slide 108 text

More about Kotlin

Slide 109

Slide 109 text

No content

Slide 110

Slide 110 text

Kotlin course at Coursera

Slide 111

Slide 111 text

Hands-on lab “Intro to coroutines & channels” http://kotl.in/hands-on

Slide 112

Slide 112 text

Have a nice Kotlin!