Speaker: Roman Elizarov
• Professional developer since 2000
• Previously developed high-perf trading software
@ Devexperts
• Teach concurrent & distributed programming
@ St. Petersburg ITMO University
• Chief judge
@ Northern Eurasia Contest / ACM ICPC
• Now team lead in Kotlin Libraries
@ JetBrains
Callbacks: before
fun requestToken(): Token {
// makes request for a token & waits
return token // returns result when received
}
1
Slide 6
Slide 6 text
Callbacks: after
fun requestTokenAsync(cb: (Token) -> Unit) {
// makes request for a token, invokes callback when done
// returns immediately
}
1
callback
Slide 7
Slide 7 text
Callbacks: before
fun requestTokenAsync(cb: (Token) -> Unit) { … }
fun createPost(token: Token, item: Item): Post {
// sends item to the server & waits
return post // returns resulting post
}
2
Slide 8
Slide 8 text
Callbacks: after
fun requestTokenAsync(cb: (Token) -> Unit) { … }
fun createPostAsync(token: Token, item: Item,
cb: (Post) -> Unit) {
// sends item to the server, invokes callback when done
// returns immediately
}
2
callback
Slide 9
Slide 9 text
Callbacks: before
fun requestTokenAsync(cb: (Token) -> Unit) { … }
fun createPostAsync(token: Token, item: Item,
cb: (Post) -> Unit) { … }
fun processPost(post: Post) { … }
fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Slide 10
Slide 10 text
Callbacks: after
fun requestTokenAsync(cb: (Token) -> Unit) { … }
fun createPostAsync(token: Token, item: Item,
cb: (Post) -> Unit) { … }
fun processPost(post: Post) { … }
fun postItem(item: Item) {
requestTokenAsync { token ->
createPostAsync(token, item) { post ->
processPost(post)
}
}
} aka “callback hell”
This is simplified. Handling
exceptions makes it a real mess
Slide 11
Slide 11 text
Futures/Promises
make it nicer
Slide 12
Slide 12 text
Futures: before
fun requestTokenAsync(cb: (Token) -> Unit) {
// makes request for a token, invokes callback when done
// returns immediately
}
1
Slide 13
Slide 13 text
Futures: after
fun requestTokenAsync(): Promise {
// makes request for a token
// returns promise for a future result immediately
}
1
future
Slide 14
Slide 14 text
Futures: before
fun requestTokenAsync(): Promise { … }
fun createPostAsync(token: Token, item: Item,
cb: (Post) -> Unit) {
// sends item to the server, invokes callback when done
// returns immediately
}
2
Slide 15
Slide 15 text
Futures: after
fun requestTokenAsync(): Promise { … }
fun createPostAsync(token: Token, item: Item): Promise {
// sends item to the server
// returns promise for a future result immediately
}
future
2
Slide 16
Slide 16 text
Futures: before
fun requestTokenAsync(): Promise { … }
fun createPostAsync(token: Token, item: Item): Promise …
fun processPost(post: Post) { … }
fun postItem(item: Item) {
requestTokenAsync { token ->
createPostAsync(token, item) { post ->
processPost(post)
}
}
}
Slide 17
Slide 17 text
Futures: after
fun requestTokenAsync(): Promise { … }
fun createPostAsync(token: Token, item: Item): Promise …
fun processPost(post: Post) { … }
fun postItem(item: Item) {
requestTokenAsync()
.thenCompose { token -> createPostAsync(token, item) }
.thenAccept { post -> processPost(post) }
}
Slide 18
Slide 18 text
Futures: after
fun requestTokenAsync(): Promise { … }
fun createPostAsync(token: Token, item: Item): Promise …
fun processPost(post: Post) { … }
fun postItem(item: Item) {
requestTokenAsync()
.thenCompose { token -> createPostAsync(token, item) }
.thenAccept { post -> processPost(post) }
}
Callbacks are still here
Slide 19
Slide 19 text
Futures: after
fun requestTokenAsync(): Promise { … }
fun createPostAsync(token: Token, item: Item): Promise …
fun processPost(post: Post) { … }
fun postItem(item: Item) {
requestTokenAsync()
.thenCompose { token -> createPostAsync(token, item) }
.thenAccept { post -> processPost(post) }
}
Composable &
propagates exceptions
No nesting indentation Callbacks are still here
Slide 20
Slide 20 text
Futures: after
fun requestTokenAsync(): Promise { … }
fun createPostAsync(token: Token, item: Item): Promise …
fun processPost(post: Post) { … }
fun postItem(item: Item) {
requestTokenAsync()
.thenCompose { token -> createPostAsync(token, item) }
.thenAccept { post -> processPost(post) }
}
But all those operators…
Slide 21
Slide 21 text
Kotlin coroutines
to the rescue
Slide 22
Slide 22 text
Coroutines: before
fun requestTokenAsync(): Promise {
// makes request for a token
// returns promise for a future result immediately
}
1
Slide 23
Slide 23 text
Coroutines: after
suspend fun requestToken(): Token {
// makes request for a token & suspends
return token // returns result when received
}
1
natural signature
Slide 24
Slide 24 text
Coroutines: before
suspend fun requestToken(): Token { … }
fun createPostAsync(token: Token, item: Item): Promise {
// sends item to the server
// returns promise for a future result immediately
}
2
Slide 25
Slide 25 text
Coroutines: after
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post {
// sends item to the server & suspends
return post // returns result when received
}
2
natural signature
Slide 26
Slide 26 text
Coroutines: before
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
fun postItem(item: Item) {
requestTokenAsync()
.thenCompose { token -> createPostAsync(token, item) }
.thenAccept { post -> processPost(post) }
}
Slide 27
Slide 27 text
Coroutines: after
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Slide 28
Slide 28 text
Coroutines: after
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Like regular code
Slide 29
Slide 29 text
Coroutines: after
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
suspension
points
Slide 30
Slide 30 text
• Regular loops
Bonus features
for ((token, item) in list) {
createPost(token, item)
}
Kotlin suspending functions
callback
Kotlin
Java/JVM
Continuation is a generic callback interface
suspend fun createPost(token: Token, item: Item): Post { … }
Object createPost(Token token, Item item, Continuation cont) { … }
interface Continuation {
val context: CoroutineContext
fun resumeWith(result: Result)
}
Slide 37
Slide 37 text
Kotlin suspending functions
callback
Kotlin
Java/JVM
suspend fun createPost(token: Token, item: Item): Post { … }
Object createPost(Token token, Item item, Continuation cont) { … }
interface Continuation {
val context: CoroutineContext
fun resumeWith(result: Result)
}
Slide 38
Slide 38 text
Kotlin suspending functions
callback
Kotlin
Java/JVM
suspend fun createPost(token: Token, item: Item): Post { … }
Object createPost(Token token, Item item, Continuation cont) { … }
interface Continuation {
val context: CoroutineContext
fun resumeWith(result: Result)
}
Slide 39
Slide 39 text
Integration
Zoo of futures on JVM
Slide 40
Slide 40 text
interface Service {
fun createPost(token: Token, item: Item): Call
}
Retrofit async
Slide 41
Slide 41 text
interface Service {
fun createPost(token: Token, item: Item): Call
}
suspend fun createPost(token: Token, item: Item): Post =
serviceInstance.createPost(token, item).await()
natural signature
Slide 42
Slide 42 text
interface Service {
fun createPost(token: Token, item: Item): Call
}
suspend fun createPost(token: Token, item: Item): Post =
serviceInstance.createPost(token, item).await()
Suspending extension function
from integration library
Slide 43
Slide 43 text
suspend fun Call.await(): T {
…
}
Slide 44
Slide 44 text
Callbacks everywhere
suspend fun Call.await(): T {
enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
// todo
}
override fun onFailure(call: Call, t: Throwable) {
// todo
}
})
}
Slide 45
Slide 45 text
suspend fun Call.await(): T = suspendCoroutine { cont ->
enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful)
cont.resume(response.body()!!)
else
cont.resumeWithException(ErrorResponse(response))
}
override fun onFailure(call: Call, t: Throwable) {
cont.resumeWithException(t)
}
})
}
Slide 46
Slide 46 text
suspend fun suspendCoroutine(block: (Continuation) -> Unit): T
Slide 47
Slide 47 text
suspend fun suspendCoroutine(block: (Continuation) -> Unit): T
Slide 48
Slide 48 text
suspend fun suspendCoroutine(block: (Continuation) -> Unit): T
Regular function
Inspired by call/cc from Scheme
Slide 49
Slide 49 text
suspend fun Call.await(): T = suspendCoroutine { cont ->
enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful)
cont.resume(response.body()!!)
else
cont.resumeWithException(ErrorResponse(response))
}
override fun onFailure(call: Call, t: Throwable) {
cont.resumeWithException(t)
}
})
}
Slide 50
Slide 50 text
Install callback
suspend fun Call.await(): T = suspendCoroutine { cont ->
enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful)
cont.resume(response.body()!!)
else
cont.resumeWithException(ErrorResponse(response))
}
override fun onFailure(call: Call, t: Throwable) {
cont.resumeWithException(t)
}
})
}
Slide 51
Slide 51 text
Install callback
suspend fun Call.await(): T = suspendCoroutine { cont ->
enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful)
cont.resume(response.body()!!)
else
cont.resumeWithException(ErrorResponse(response))
}
override fun onFailure(call: Call, t: Throwable) {
cont.resumeWithException(t)
}
})
}
Slide 52
Slide 52 text
Analyze response
suspend fun Call.await(): T = suspendCoroutine { cont ->
enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful)
cont.resume(response.body()!!)
else
cont.resumeWithException(ErrorResponse(response))
}
override fun onFailure(call: Call, t: Throwable) {
cont.resumeWithException(t)
}
})
}
Slide 53
Slide 53 text
Analyze response
suspend fun Call.await(): T = suspendCoroutine { cont ->
enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful)
cont.resume(response.body()!!)
else
cont.resumeWithException(ErrorResponse(response))
}
override fun onFailure(call: Call, t: Throwable) {
cont.resumeWithException(t)
}
})
}
That’s all
Slide 54
Slide 54 text
Coroutine builders
Slide 55
Slide 55 text
Coroutines revisited
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Slide 56
Slide 56 text
Coroutines revisited
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Slide 57
Slide 57 text
Coroutines revisited
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Error: Suspend function 'requestToken' should be called only from
a coroutine or another suspend function
Slide 58
Slide 58 text
Coroutines revisited
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Can suspend execution
Slide 59
Slide 59 text
Coroutines revisited
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Can suspend execution
A regular function cannot
Slide 60
Slide 60 text
Coroutines revisited
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Can suspend execution
A regular function cannot
One cannot simply invoke a
suspending function
Slide 61
Slide 61 text
Launch
fun postItem(item: Item) {
GlobalScope.launch {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
}
coroutine builder
Slide 62
Slide 62 text
fun postItem(item: Item) {
GlobalScope.launch {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
}
Fire and forget!
Slide 63
Slide 63 text
fun postItem(item: Item) {
GlobalScope.launch {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
}
Fire and forget!
We launch for its
side effects
Slide 64
Slide 64 text
fun postItem(item: Item) {
GlobalScope.launch {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
}
Returns immediately, coroutine works
in background thread pool
Slide 65
Slide 65 text
fun postItem(item: Item) {
GlobalScope.launch {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
}
Slide 66
Slide 66 text
fun postItem(item: Item) {
GlobalScope.launch(Dispatchers.Main) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
}
Dispatcher
Just specify the dispatcher
Slide 67
Slide 67 text
fun postItem(item: Item) {
GlobalScope.launch(Dispatchers.Main) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
}
Dispatcher
And it gets executed on the Main thread
Slide 68
Slide 68 text
Where’s the magic of launch?
Slide 69
Slide 69 text
fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
block: suspend () -> Unit
): Job { … }
A regular function
Slide 70
Slide 70 text
fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
block: suspend () -> Unit
): Job { … } suspending lambda
Slide 71
Slide 71 text
fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
block: suspend () -> Unit
): Job { … }
Slide 72
Slide 72 text
async / await
The classic approach
Slide 73
Slide 73 text
Kotlin-way
suspend fun postItem(item: Item) {
val token = requestToken()
val post = createPost(token, item)
processPost(post)
}
Kotlin
suspend fun requestToken(): Token { … }
suspend fun createPost(token: Token, item: Item): Post { … }
fun processPost(post: Post) { … }
Slide 74
Slide 74 text
async Task postItem(Item item) {
var token = await requestToken();
var post = await createPost(token, item);
processPost(post);
}
Classic-way
C# approach to the same problem (also
Python, TS, Dart, coming to JS)
C#
async Task requestToken() { … }
async Task createPost(Token token, Item item) { … }
void processPost(Post post) { … }
Slide 75
Slide 75 text
async Task postItem(Item item) {
var token = await requestToken();
var post = await createPost(token, item);
processPost(post);
}
Classic-way
mark with async
C#
async Task requestToken() { … }
async Task createPost(Token token, Item item) { … }
void processPost(Post post) { … }
Slide 76
Slide 76 text
async Task postItem(Item item) {
var token = await requestToken();
var post = await createPost(token, item);
processPost(post);
}
Classic-way
use await to suspend
C#
async Task requestToken() { … }
async Task createPost(Token token, Item item) { … }
void processPost(Post post) { … }
Use-case for async
var promise1 = loadImageAsync(name1);
var promise2 = loadImageAsync(name2);
async Task loadImageAsync(String name) { … }
Start multiple operations
concurrently
C#
Slide 83
Slide 83 text
Use-case for async
var promise1 = loadImageAsync(name1);
var promise2 = loadImageAsync(name2);
var image1 = await promise1;
var image2 = await promise2;
async Task loadImageAsync(String name) { … }
and then wait for them
C#
Slide 84
Slide 84 text
Use-case for async
var result = combineImages(image1, image2);
C#
var promise1 = loadImageAsync(name1);
var promise2 = loadImageAsync(name2);
var image1 = await promise1;
var image2 = await promise2;
async Task loadImageAsync(String name) { … }
Slide 85
Slide 85 text
Kotlin async function
fun loadImageAsync(name: String): Deferred =
GlobalScope.async { … }
Kotlin
Slide 86
Slide 86 text
Kotlin async function
fun loadImageAsync(name: String): Deferred =
GlobalScope.async { … }
Kotlin
A regular function
Slide 87
Slide 87 text
Kotlin async function
fun loadImageAsync(name: String): Deferred =
GlobalScope.async { … }
Kotlin’s future type
Kotlin
Slide 88
Slide 88 text
Kotlin async function
fun loadImageAsync(name: String): Deferred =
GlobalScope.async { … }
async coroutine builder
Kotlin
Slide 89
Slide 89 text
fun loadImageAsync(name: String): Deferred =
GlobalScope.async { … }
val deferred1 = loadImageAsync(name1)
val deferred2 = loadImageAsync(name2)
Start multiple operations
concurrently
Kotlin
Slide 90
Slide 90 text
fun loadImageAsync(name: String): Deferred =
GlobalScope.async { … }
val deferred1 = loadImageAsync(name1)
val deferred2 = loadImageAsync(name2)
val image1 = deferred1.await()
val image2 = deferred2.await()
and then wait for them
await function
Suspends until deferred is complete
Kotlin
Slide 91
Slide 91 text
fun loadImageAsync(name: String): Deferred =
GlobalScope.async { … }
val deferred1 = loadImageAsync(name1)
val deferred2 = loadImageAsync(name2)
val image1 = deferred1.await()
val image2 = deferred2.await()
val result = combineImages(image1, image2)
Kotlin
But what if this crashes?
Crash?
Slide 92
Slide 92 text
fun loadImageAsync(name: String): Deferred =
GlobalScope.async { … }
val deferred1 = loadImageAsync(name1)
val deferred2 = loadImageAsync(name2)
val image1 = deferred1.await()
val image2 = deferred2.await()
val result = combineImages(image1, image2)
Kotlin
Crash?
This one leaks
But what if this crashes?
Slide 93
Slide 93 text
Idiomatic: Using async function when needed
suspend fun loadImage(name: String): Image { … }
Is defined as suspending function, not async
Slide 94
Slide 94 text
Idiomatic: Using async function when needed
suspend fun loadImage(name: String): Image { … }
suspend fun loadAndCombine(name1: String, name2: String): Image =
coroutineScope {
val deferred1 = async { loadImage(name1) }
val deferred2 = async { loadImage(name2) }
combineImages(deferred1.await(), deferred2.await())
}
Structured concurrency
Slide 95
Slide 95 text
Idiomatic: Using async function when needed
suspend fun loadImage(name: String): Image { … }
suspend fun loadAndCombine(name1: String, name2: String): Image =
coroutineScope {
val deferred1 = async { loadImage(name1) }
val deferred2 = async { loadImage(name2) }
combineImages(deferred1.await(), deferred2.await())
}
Slide 96
Slide 96 text
Idiomatic: Using async function when needed
suspend fun loadImage(name: String): Image { … }
suspend fun loadAndCombine(name1: String, name2: String): Image =
coroutineScope {
val deferred1 = async { loadImage(name1) }
val deferred2 = async { loadImage(name2) }
combineImages(deferred1.await(), deferred2.await())
}
Slide 97
Slide 97 text
Idiomatic: Using async function when needed
suspend fun loadImage(name: String): Image { … }
suspend fun loadAndCombine(name1: String, name2: String): Image =
coroutineScope {
val deferred1 = async { loadImage(name1) }
val deferred2 = async { loadImage(name2) }
combineImages(deferred1.await(), deferred2.await())
}
Structured concurrency
suspend fun loadImage(name: String): Image { … }
suspend fun loadAndCombine(name1: String, name2: String): Image =
coroutineScope {
val deferred1 = async { loadImage(name1) }
val deferred2 = async { loadImage(name2) }
combineImages(deferred1.await(), deferred2.await())
}
Slide 101
Slide 101 text
Crash
suspend fun loadImage(name: String): Image { … }
suspend fun loadAndCombine(name1: String, name2: String): Image =
coroutineScope {
val deferred1 = async { loadImage(name1) }
val deferred2 = async { loadImage(name2) }
combineImages(deferred1.await(), deferred2.await())
}
Crashes?
Slide 102
Slide 102 text
Cancels scope
suspend fun loadImage(name: String): Image { … }
suspend fun loadAndCombine(name1: String, name2: String): Image =
coroutineScope {
val deferred1 = async { loadImage(name1) }
val deferred2 = async { loadImage(name2) }
combineImages(deferred1.await(), deferred2.await())
}
Cancels
Slide 103
Slide 103 text
Cancels children
suspend fun loadImage(name: String): Image { … }
suspend fun loadAndCombine(name1: String, name2: String): Image =
coroutineScope {
val deferred1 = async { loadImage(name1) }
val deferred2 = async { loadImage(name2) }
combineImages(deferred1.await(), deferred2.await())
}
Cancels
Slide 104
Slide 104 text
Kotlin suspending functions
may use concurrency internally,
but don’t leak it
Concurrency needs to be structured
Slide 105
Slide 105 text
Parallelism is optional
Slide 106
Slide 106 text
Beyond asynchronous code
Kotlin’s approach to generate/yield – synchronous coroutines
Slide 107
Slide 107 text
Fibonacci sequence
val fibonacci: Sequence = …
Slide 108
Slide 108 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
Slide 109
Slide 109 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
println(fibonacci.take(10).toList())
Slide 110
Slide 110 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
println(fibonacci.take(10).toList())
>> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
Slide 111
Slide 111 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
A coroutine builder with
restricted suspension
Slide 112
Slide 112 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
A suspending function in
the scope of buildSequence
Slide 113
Slide 113 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
println(fibonacci.take(10).toList())
Synchronous
Slide 114
Slide 114 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
Slide 115
Slide 115 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next())
Slide 116
Slide 116 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next())
Slide 117
Slide 117 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next())
Slide 118
Slide 118 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next())
Slide 119
Slide 119 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next()) // 1
Slide 120
Slide 120 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next()) // 1
println(iter.next())
Slide 121
Slide 121 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next()) // 1
println(iter.next())
Slide 122
Slide 122 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next()) // 1
println(iter.next())
Slide 123
Slide 123 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next()) // 1
println(iter.next())
Slide 124
Slide 124 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next()) // 1
println(iter.next())
Slide 125
Slide 125 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next()) // 1
println(iter.next()) // 1
Slide 126
Slide 126 text
Fibonacci sequence
val fibonacci = sequence {
var cur = 1
var next = 1
while (true) {
yield(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
val iter = fibonacci.iterator()
println(iter.next()) // 1
println(iter.next()) // 1 etc ad infinum
Slide 127
Slide 127 text
Sharing state?
Slide 128
Slide 128 text
Shared Mutable State
Operations
Operations
Operations
Slide 129
Slide 129 text
Shared Mutable State
Operations
Operations
Operations
Needs
synchronization
Slide 130
Slide 130 text
Shared Mutable State
@stefanobaghino
Slide 131
Slide 131 text
Communicating
Sequential
Processes
Slide 132
Slide 132 text
Concurrent Fibonacci sequence
val fibonacci = GlobalScope.produce {
var cur = 1
var next = 1
while (true) {
send(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
Asynchronous
(can be in different thread)
Slide 133
Slide 133 text
Concurrent Fibonacci sequence
val fibonacci = GlobalScope.produce {
var cur = 1
var next = 1
while (true) {
send(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
fun main(args: Array) = runBlocking {
println(fibonacci.receive())
}
Another coroutine
Asynchronous
(can be in different thread)
Slide 134
Slide 134 text
Concurrent Fibonacci sequence
val fibonacci = GlobalScope.produce {
var cur = 1
var next = 1
while (true) {
send(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
fun main(args: Array) = runBlocking {
println(fibonacci.receive())
}
Another coroutine
Receives from channel
Asynchronous
(can be in different thread)
Slide 135
Slide 135 text
Concurrent Fibonacci sequence
val fibonacci = GlobalScope.produce {
var cur = 1
var next = 1
while (true) {
send(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
fun main(args: Array) = runBlocking {
println(fibonacci.receive()) // 1
}
Slide 136
Slide 136 text
Concurrent Fibonacci sequence
val fibonacci = GlobalScope.produce {
var cur = 1
var next = 1
while (true) {
send(cur)
val tmp = cur + next
cur = next
next = tmp
}
}
fun main(args: Array) = runBlocking {
println(fibonacci.receive()) // 1
println(fibonacci.receive()) // 1
}
etc ad infinum
Slide 137
Slide 137 text
Library vs Language
Keeping the core language small