Should it be routine to use
Coroutines?
Stefan Brosteanu
Agenda
• Styles of writing code

• Deep dive into the inner workings of coroutines 

• Integration with other libraries 

• Short comparison to RxJava
Prologue
Refresh token
Post item using refreshed token
Refresh token
Post item using refreshed token
Refresh token
Post item using refreshed token
Refresh token
Post item using refreshed token
fun updateAccount(updatedUser: User) {
val token = refreshToken()
postUpdate(token, updatedUser)
}
fun updateAccount(updatedUser: User) {
val token = refreshToken()
postUpdate(token, updatedUser)
}
Refresh token
Post Item with refreshed
token
fun updateAccount(updatedUser: User) {
val token = refreshToken()
postUpdate(token, updatedUser)
}
Direct style
fun updateAccount(updatedUser: User) {
val token = refreshToken()
postUpdate(token, updatedUser)
}
Direct style
Action
fun updateAccount(updatedUser: User) {
val token = refreshToken()
postUpdate(token, updatedUser)
}
Direct style
Continuation
fun updateAccount(updatedUser: User) {
val token = refreshToken()
postUpdate(token, updatedUser)
}
Direct style
fun updateAccount(updatedUser: User) {
refreshToken { token ->
postUpdate(token, updatedUser)
}
}
fun updateAccount(updatedUser: User) {
refreshToken { token ->
postUpdate(token, updatedUser)
}
}
Continuation Passing Style
Asynchronous programming
Asynchronous Programming
• Async tasks

• Loaders

• Callbacks

• Promises

• Futures

• Reactive Extensions
Async tasks
• Labeled as “Painless Threading”

• Async Tasks don’t work well with orientations changes or might have
problems with the Lifecycle

• Limited to 138 concurrent tasks
Loaders
• Never really caught on

• Trying to solve the problem of running asynchronous operations within the
Activity or Fragments
Callbacks
• Error handling is cumbersome

• The dreaded Callback Hell
Promises/Futures
• introduce concept of operators

• relies on introspecting the value that needs to be returned
fun updateAccount(updatedUser: User) {
refreshToken()
.thenCompose { token ->
postUpdate(token, updatedUser)
}
}
fun refreshToken(): Promise<Token> {
...
return promise
}
Reactive Extensions
• simplifies the way you do async/threaded work

• simple to compose streams of data

• avoid callback hell

• a downside is that you shift from the normal programming model
Coroutines
What are coroutines?
• basically lightweight threads

• provide the same way of writing code both for async and sync

• exceptions handling, loops, etc. work like in synchronous code
What are coroutines?
suspend fun updateAccount(updatedUser: User) {
val token = refreshToken()
postUpdate(token, updatedUser)
}
How do coroutines work?
suspend fun refreshToken(): Token {
...
}
Object refreshToken(Continuation<Token> cont) {
...
}
Callback
interface Continuation<in T> {
val context: CoroutineContext
fun resume(value: T)
fun resumeWithException(exception: Throwable)
}
Is that really it?
suspend fun updateAccount(updatedUser: User) {
0 val token = refreshToken()
1 postUpdate(token, updatedUser)
2 }
class StateMachine(val updatedUser: User,
val updateAccountCallback: Continuation<Unit>)
: Continuation<Any?> {
var label: Int = 0
var token: String? = null
}
Deeper
suspend fun updateAccount(updatedUser: User) {
0 val token = refreshToken()
1 postUpdate(token, updatedUser)
2 }
when (sm.label) {
0 -> { sm.label = 1; refreshToken(sm) }
1 -> { sm.label = 2;
sm.token = value as String;
postUpdate(sm.token!!, updatedUser, sm)
}
2 -> { sm.updateAccountCallback.resume(Unit) }
}
Label is set to 0
Deeper
suspend fun updateAccount(updatedUser: User) {
0 val token = refreshToken()
1 postUpdate(token, updatedUser)
2 }
when (sm.label) {
0 -> { sm.label = 1; refreshToken(sm) }
1 -> { sm.label = 2;
sm.token = value as String;
postUpdate(sm.token!!, updatedUser, sm)
}
2 -> { sm.updateAccountCallback.resume(Unit) }
}
Label is set to 1
Deeper
suspend fun updateAccount(updatedUser: User) {
0 val token = refreshToken()
1 postUpdate(token, updatedUser)
2 }
when (sm.label) {
0 -> { sm.label = 1; refreshToken(sm) }
1 -> { sm.label = 2;
sm.token = value as String;
postUpdate(sm.token!!, updatedUser, sm)
}
2 -> { sm.updateAccountCallback.resume(Unit) }
}
Label is set to 2
Coroutine builders
suspend fun updateAccount(updatedUser: User) {
val token = refreshToken()
postUpdate(token, updatedUser)
}
Coroutine builders
fun updateAccount(updatedUser: User) {
launch {
val token = refreshToken()
postUpdate(token, updatedUser)
}
}
Coroutine builders
• launch 

• async

• withContext

• runBlocking
Coroutine context
fun updateAccount(updatedUser: User) {
launch {
val token = refreshToken()
postUpdate(token, updatedUser)
withContext (UI) {
// update UI
}
}
}
Coroutine context
• Unconfined

• CommonPool

• UI
Can they play well with others?
• Short answer: YES

• Long answer: with most or all libraries that use some sort of Future or
expose some kind of callback

• basically you need to create and/or apply a await extension function
How?
interface ApiService {
fun postUpdate(token: Token, updatedUser: User): Call<User>
}
How?
interface ApiService {
fun postUpdate(token: Token, updatedUser: User): Call<User>
}
suspend fun updateAccount(token: Token, updatedUser: User): User {
apiServiceInstance.updateAccount(token, updatedUser).await()
}
How?
suspend fun <T> Call.<T>.await(): T {
...
}
How?
suspend fun <T> Call<T>.await(): T {
enqueue(object : Callback<T> {
override fun onFailure(call: Call<T>, t: Throwable) {
TODO("not implemented")
}
override fun onResponse(call: Call<T>, response: Response<T>) {
TODO("not implemented")
}
})
}
How?
public suspend inline fun <T> suspendCoroutine(crossinline block: (Continuation<T>) -> Unit): T =
suspendCoroutineOrReturn { c: Continuation<T> ->
val safe = SafeContinuation(c)
block(safe)
safe.getResult()
}
How?
suspend fun <T> Call<T>.await(): T = suspendCoroutine { continuation ->
enqueue(object : Callback<T> {
override fun onFailure(call: Call<T>, t: Throwable) {
continuation.resumeWithException(t)
}
override fun onResponse(call: Call<T>, response: Response<T>) {
if (response.isSuccessful) {
continuation.resume(response.body()!!)
} else {
continuation.resumeWithException(Error(response.errorBody()!!))
}
}
})
}
How? - Sidenote
• JetBrains provides some out of the box integrations
How does it stack up against RxJava?
• Does it replace Rx?

• Is it better than Rx?
Why shouldn’t you use Rx?
• fluent API, but it leads to hard to read code and changing it might be
complex

• creating modular code that can be composed and still be readable is a
pain

• it’s overkill, most of the times
Why shouldn’t you use coroutines?
• if you’ve already learned Rx and the codebase is heavily relying on it

• sometimes composing and pub/sub-ing is easier with Rx

• if you’re codebase is written in Java

• community of developers using Rx is a tad larger (more questions on SO)
What else is there?
What else is there?
• Cancellation

• Composition

• Channels 

• Actors

• Coroutine scope
Epilogue
Epilogue
• Direct Style and Continuation Passing Style ✅ 

• Deep dive into the inner workings of coroutines ✅ 

• Integration with other libraries ✅ 

• Short comparison to RxJava ✅
Should it be routine to use
coroutines?
Resources
• https://kotlinlang.org/docs/reference/coroutines.html

• https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-
informal.md

• https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-
guide.md

• KotlinConf 2017 - Deep Dive into Coroutines on JVM by Roman Elizarov
Thank you!
Stefan Brosteanu
@stef.brosteanu
sbrosteanu

Should it be routine to use coroutines?