SlideShare a Scribd company logo
Kotlin	Coroutines	Reloaded
Presented	at	JVM	Language	Summit,	2017
/Roman	Elizarov	@	JetBrains
Speaker:	Roman	Elizarov
• 16+	years	experience
• Previously	developed	high-perf	trading	software	
@	Devexperts
• Teach	concurrent	&	distributed	programming	
@	St.	Petersburg	ITMO	University
• Chief	judge	
@	Northeastern	European	Region	of	ACM	ICPC	
• Now	work	on	Kotlin	
@	JetBrains
Agenda
• Recap	of	Kotlin	coroutines	prototype
• Presented	@	JVMLS,	2016	by	Andrey	Breslav
• The	issues	in	the	prototype	design
• and	the	solutions	that	were	found
• Design	released	to	public	in	Kotlin	1.1
• Evolved	coroutines	support	libraries
• Challenges	&	future	directions
Recap	of	Kotlin	coroutines	
prototype
Presented	@	JVMLS,	2016	by	Andrey	Breslav
Async	the	C#	(JS,	TS,	Dart,	etc)	way
async Task<String> Work() { … }
async Task MoreWork()
{
Console.WriteLine("Work started");
var str = await Work();
Console.WriteLine($"Work completed {str}");
}
Async	the	C#	(JS,	TS,	Dart,	etc)	way
async Task<String> work() { … }
async Task MoreWork()
{
Console.WriteLine("Work started");
var str = await Work();
Console.WriteLine($"Work completed {str}");
}
Async	the	Kotlin	way	(prototype)
fun work(): CompletableFuture<String> { … }
fun moreWork() = async {
println("Work started")
val str = await(work())
println("Work completed: $str")
}
Async	the	Kotlin	way	(prototype)
fun work(): CompletableFuture<String> { … }
fun moreWork() = async {
println("Work started")
val str = await(work())
println("Work completed: $str")
}
Functions	vs	Keywords
Extensibility
Runs	on	stock	JVM	1.6+
Purely	local	-- no	global	
bytecode	transforms
Suspending	functions
A	grand	unification	between	async/await	and	generate/yield
Suspending	functions:	use
val str = await(work())
Suspending	functions:	use
val str = await(work())
CompletableFuture<String>
// String result
Suspending	functions:	declare	(prototype)
val str = await(work())
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Unit
CompletableFuture<String>
// String result
Suspending	functions:	declare	(prototype)
val str = await(work())
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Unit
CompletableFuture<String>
callback void
// String result
Magic	signature	transformation
Suspending	functions:	declare	(prototype)
val str = await(work())
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Unit
CompletableFuture<String>
callback void
// String result
Continuation	is	a	generic	callback	interface
interface Continuation<in T> {
fun resume(value: T)
fun resumeWithException(exception: Throwable)
}
Suspending	functions:	implement	(prototype)
val str = await(work())
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>) {
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
CompletableFuture<String>
// String result
Suspending	functions:	implement	(prototype)
val str = await(work())
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>) {
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
CompletableFuture<String>
// String result
Suspending	functions:	implement	(prototype)
val str = await(work())
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>) {
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
CompletableFuture<String>
// String result
Suspending	functions:	implement	(prototype)
val str = await(work())
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>) {
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
CompletableFuture<String>
// String result
Suspending	functions:	implement	(prototype)
val str = await(work())
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>) {
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
CompletableFuture<String>
// String result
Simple,	but	wrong!
A	problematic	example
Where	grand	vision	meets	reality
A	problematic	example
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>) {
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
fun problem() = async {
repeat(10_000) {
await(work())
}
}
A	problematic	example
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>) {
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
fun problem() = async {
repeat(10_000) {
await(work())
}
}
What	if	work()	always	returns	a	
future	that	is	already	complete?
A	problematic	example
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>) {
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
fun problem() = async {
repeat(10_000) {
await(work())
}
}
stack
problem$stateMachine
A	problematic	example
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>) {
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
fun problem() = async {
repeat(10_000) {
await(work())
}
}
stack
problem$stateMachine
await
A	problematic	example
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>) {
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
fun problem() = async {
repeat(10_000) {
await(work())
}
}
stack
problem$stateMachine
await
CompletableFuture.whenComplete
A	problematic	example
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>) {
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
fun problem() = async {
repeat(10_000) {
await(work())
}
}
stack
problem$stateMachine
await
CompletableFuture.whenComplete
await$lambda
A	problematic	example
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>) {
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
fun problem() = async {
repeat(10_000) {
await(work())
}
}
stack
problem$stateMachine
await
CompletableFuture.whenComplete
await$lambda
A	problematic	example
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>) {
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
fun problem() = async {
repeat(10_000) {
await(work())
}
}
stack
problem$stateMachine
await
CompletableFuture.whenComplete
await$lambda
ContinuationImpl.resume
A	problematic	example
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>) {
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
fun problem() = async {
repeat(10_000) {
await(work())
}
}
stack
problem$stateMachine
await
CompletableFuture.whenComplete
await$lambda
ContinuationImpl.resume
problem$stateMachine
A	problematic	example
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>) {
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
fun problem() = async {
repeat(10_000) {
await(work())
}
}
stack
problem$stateMachine
await
CompletableFuture.whenComplete
await$lambda
ContinuationImpl.resume
problem$stateMachine
await
A	problematic	example
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>) {
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
fun problem() = async {
repeat(10_000) {
await(work())
}
}
stack
problem$stateMachine
await
CompletableFuture.whenComplete
await$lambda
ContinuationImpl.resume
problem$stateMachine
await
…
StackOverflowError
A	solution
A	difference	between	knowing	the	path	&	walking	the	path.
A	solution
val str = await(work())
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Unit
CompletableFuture<String>
// String result
A	solution	(0):	stack	unwind	convention
val str = await(work())
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Any?
CompletableFuture<String>
// String result
A	solution	(0)
val str = await(work())
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Any?
CompletableFuture<String>
// String result
T | COROUTINE_SUSPENDED
A	solution	(0)
val str = await(work())
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Any?
CompletableFuture<String>
// String result
T | COROUTINE_SUSPENDED
Did	not	suspend	->	Returns	result
A	solution	(0)
val str = await(work())
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Any?
CompletableFuture<String>
// String result
T | COROUTINE_SUSPENDED
Did	not	suspend	->	Returns	result
Did	suspend	->	WILL	invoke	continuation
A	solution	(0)
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Any? {
…
}
A	solution?
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Any? {
val consensus = AtomicReference<Any?>(UNDECIDED)
f.whenComplete { value, exception ->
if (exception != null) {
if (!consensus.compareAndSet(UNDECIDED, Fail(exception)))
c.resumeWithException(exception)
} else {
if (!consensus.compareAndSet(UNDECIDED, value))
c.resume(value!!)
}
}
consensus.compareAndSet(UNDECIDED, COROUTINE_SUSPENDED)
val result = consensus.get()
if (result is Fail) throw result.exception
return result
}
A	solution?
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Any? {
val consensus = AtomicReference<Any?>(UNDECIDED)
f.whenComplete { value, exception ->
if (exception != null) {
if (!consensus.compareAndSet(UNDECIDED, Fail(exception)))
c.resumeWithException(exception)
} else {
if (!consensus.compareAndSet(UNDECIDED, value))
c.resume(value!!)
}
}
consensus.compareAndSet(UNDECIDED, COROUTINE_SUSPENDED)
val result = consensus.get()
if (result is Fail) throw result.exception
return result
}
Wat?
A	solution	(1):	Call/declaration	fidelity
A	solution	(1)
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Any?
A	solution	(1)
suspend fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Any?
suspend fun <T> await(f: CompletableFuture<T>): T
natural	signature
A	solution	(1)
fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Any?
suspend fun <T> await(f: CompletableFuture<T>): T
Compiles	as	(on	JVM)
A	solution	(1)
fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Any?
suspend fun <T> await(f: CompletableFuture<T>): T
Compiles	as	(on	JVM)
CPS	Transformation
A	solution	(1)
fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Any?
suspend fun <T> await(f: CompletableFuture<T>)
suspend fun <T> await(f: CompletableFuture<T>): T =
suspendCoroutineOrReturn { c ->
…
}
Recover	continuation
A	solution	(1)
fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Any?
suspend fun <T> await(f: CompletableFuture<T>)
suspend fun <T> await(f: CompletableFuture<T>): T =
suspendCoroutineOrReturn { c ->
…
}
Inspired	by	call/cc	from	Scheme
Recover	continuation
A	solution	(1)
fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Any?
suspend fun <T> await(f: CompletableFuture<T>)
suspend fun <T> await(f: CompletableFuture<T>): T =
suspendCoroutineOrReturn { c ->
…
}
Works	as
Inspired	by	call/cc	from	Scheme
A	solution	(1)
suspend fun <T> await(f: CompletableFuture<T>): T =
suspendCoroutineOrReturn { c ->
…
}
A	solution	(1)
suspend fun <T> await(f: CompletableFuture<T>): T =
suspendCoroutineOrReturn { c ->
…
}
inline suspend fun <T> suspendCoroutineOrReturn(
crossinline block: (Continuation<T>) -> Any?): T
A	solution	(1)
suspend fun <T> await(f: CompletableFuture<T>): T =
suspendCoroutineOrReturn { c ->
…
}
inline suspend fun <T> suspendCoroutineOrReturn(
crossinline block: (Continuation<T>) -> Any?): T
T | COROUTINE_SUSPENDED
A	solution	(1)
suspend fun <T> await(f: CompletableFuture<T>): T =
suspendCoroutineOrReturn { c ->
…
}
inline suspend fun <T> suspendCoroutineOrReturn(
crossinline block: (Continuation<T>) -> Any?): T
Intrinsic
T | COROUTINE_SUSPENDED
A	solution	(1)
suspend fun <T> await(f: CompletableFuture<T>): T =
suspendCoroutineOrReturn { c ->
…
}
inline suspend fun <T> suspendCoroutineOrReturn(
crossinline block: (Continuation<T>) -> Any?): T
fun <T> suspendCoroutineOrReturn(
crossinline block: (Continuation<T>) -> Any?,
c: Continuation<T>): Any? =
block(c)
Compiles	as	(on	JVM)
Intrinsic
CPS	Transformation
A	solution	(1)
suspend fun <T> await(f: CompletableFuture<T>): T =
suspendCoroutineOrReturn { c ->
…
}
inline suspend fun <T> suspendCoroutineOrReturn(
crossinline block: (Continuation<T>) -> Any?): T
fun <T> suspendCoroutineOrReturn(
crossinline block: (Continuation<T>) -> Any?,
c: Continuation<T>): Any? =
block(c)
Compiles	as	(on	JVM)
Intrinsic
CPS	Transformation
A	solution	(2):	Tail	suspension
A	solution	(2)
suspend fun <T> await(f: CompletableFuture<T>): T =
suspendCoroutineOrReturn { c ->
…
}
Tail	suspend	invocation:
Continuation	pass-through
A	solution	(2)
suspend fun <T> await(f: CompletableFuture<T>): T =
suspendCoroutineOrReturn { c ->
…
}
fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Any? =
suspendCoroutineOrReturn(c) { c ->
…
}
Tail	suspend	invocation:
Continuation	pass-through
Compiles	as	(on	JVM)
CPS	Transformation
A	solution	(2)
suspend fun <T> await(f: CompletableFuture<T>): T =
suspendCoroutineOrReturn { c ->
…
}
fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Any? =
suspendCoroutineOrReturn(c) { c ->
…
}
Tail	suspend	invocation:
Continuation	pass-through
Compiles	as	(on	JVM)
CPS	Transformation
A	solution	(2)
suspend fun <T> await(f: CompletableFuture<T>): T =
suspendCoroutineOrReturn { c ->
…
}
fun <T> await(f: CompletableFuture<T>, c: Continuation<T>): Any? {
…
}
Tail	suspend	invocation:
Continuation	pass-through
Compiles	as	(on	JVM)
CPS	Transformation
A	solution	(3):	Abstraction
A	solution	(3)
public inline suspend fun <T> suspendCoroutine(
crossinline block: (Continuation<T>) -> Unit): T =
suspendCoroutineOrReturn { c: Continuation<T> ->
val safe = SafeContinuation(c)
block(safe)
safe.getResult()
}
A	solution	(3)
public inline suspend fun <T> suspendCoroutine(
crossinline block: (Continuation<T>) -> Unit): T =
suspendCoroutineOrReturn { c: Continuation<T> ->
val safe = SafeContinuation(c)
block(safe)
safe.getResult()
}
A	solution	(3)
public inline suspend fun <T> suspendCoroutine(
crossinline block: (Continuation<T>) -> Unit): T =
suspendCoroutineOrReturn { c: Continuation<T> ->
val safe = SafeContinuation(c)
block(safe)
safe.getResult()
}
Any?	Is	gone
A	solution	(3)
public inline suspend fun <T> suspendCoroutine(
crossinline block: (Continuation<T>) -> Unit): T =
suspendCoroutineOrReturn { c: Continuation<T> ->
val safe = SafeContinuation(c)
block(safe)
safe.getResult()
}
Encapsulates	result	
consensus	algorithm
A	solution	(4):	Putting	it	all	together
A	solution	(4)
suspend fun <T> await(f: CompletableFuture<T>): T =
suspendCoroutine { c ->
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
Looks	simple,	works	correctly!
Recap	steps	to	solution
• T	|	COROUTINE_SUSPENDED	(Any?)	to	allow	invocations	that	
do	not	suspend	and	thus	avoid	StackOverflowError
• Call/declaration	fidelity	via	CPS	transformation
• Introduce	call/cc	(suspendCoroutineOrReturn)	to	recover	
hidden	continuation
• Tail	call	invocation	support	to	recover	prototype	semantics
• Use	abstraction	(suspendCoroutine)	to	hide	implementation	
complexities	from	end-users
The	final	touch:	await	extension
suspend fun <T> await(f: CompletableFuture<T>): T =
suspendCoroutine { c ->
f.whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
The	final	touch:	await	extension
suspend fun <T> CompletableFuture<T>.await(): T =
suspendCoroutine { c ->
whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
The	final	touch:	await	extension
suspend fun <T> CompletableFuture<T>.await(): T =
suspendCoroutine { c ->
whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
fun moreWork() = async {
println("Work started")
val str = await(work())
println("Work completed: $str")
}
The	final	touch:	await	extension
suspend fun <T> CompletableFuture<T>.await(): T =
suspendCoroutine { c ->
whenComplete { value, exception ->
if (exception != null) c.resumeWithException(exception)
else c.resume(value!!)
}
}
fun moreWork() = async {
println("Work started")
val str = work().await()
println("Work completed: $str")
}
Reads	left-to-right	just	like	it	executes
Coroutine	builders
The	mystery	of	inception
Coroutine	builders	(prototype)
fun <T> async(
coroutine c: FutureController<T>.() -> Continuation<Unit>
): CompletableFuture<T> {
val controller = FutureController<T>()
c(controller).resume(Unit)
return controller.future
}
Coroutine	builders	(prototype)
fun <T> async(
coroutine c: FutureController<T>.() -> Continuation<Unit>
): CompletableFuture<T> {
val controller = FutureController<T>()
c(controller).resume(Unit)
return controller.future
}
A	special	modifier
Coroutine	builders	(prototype)
fun <T> async(
coroutine c: FutureController<T>.() -> Continuation<Unit>
): CompletableFuture<T> {
val controller = FutureController<T>()
c(controller).resume(Unit)
return controller.future
}
Magic	signature	transformation
Coroutine	builders	(prototype)
fun <T> async(
coroutine c: FutureController<T>.() -> Continuation<Unit>
): CompletableFuture<T> {
val controller = FutureController<T>()
c(controller).resume(Unit)
return controller.future
}
A	boilerplate	to	start	coroutine
Coroutine	builders	(prototype)
fun <T> async(
coroutine c: FutureController<T>.() -> Continuation<Unit>
): CompletableFuture<T> { … }
class FutureController<T> {
val future = CompletableFuture<T>()
operator fun handleResult(value: T, c: Continuation<Nothing>) {
future.complete(value)
}
operator fun handleException(exception: Throwable,
c: Continuation<Nothing>) {
future.completeExceptionally(exception)
}
}
Coroutine	builders	(prototype)
fun <T> async(
coroutine c: FutureController<T>.() -> Continuation<Unit>
): CompletableFuture<T> { … }
class FutureController<T> {
val future = CompletableFuture<T>()
operator fun handleResult(value: T, c: Continuation<Nothing>) {
future.complete(value)
}
operator fun handleException(exception: Throwable,
c: Continuation<Nothing>) {
future.completeExceptionally(exception)
}
}
Coroutine	builders	(prototype)
fun <T> async(
coroutine c: FutureController<T>.() -> Continuation<Unit>
): CompletableFuture<T> { … }
class FutureController<T> {
val future = CompletableFuture<T>()
operator fun handleResult(value: T, c: Continuation<Nothing>) {
future.complete(value)
}
operator fun handleException(exception: Throwable,
c: Continuation<Nothing>) {
future.completeExceptionally(exception)
}
}
was	never	used
Coroutine	builders	(prototype)
fun <T> async(
coroutine c: FutureController<T>.() -> Continuation<Unit>
): CompletableFuture<T> { … }
class FutureController<T> {
val future = CompletableFuture<T>()
operator fun handleResult(value: T) {
future.complete(value)
}
operator fun handleException(exception: Throwable) {
future.completeExceptionally(exception)
}
}
Coroutine	builders	(prototype)
fun <T> async(
coroutine c: FutureController<T>.() -> Continuation<Unit>
): CompletableFuture<T> { … }
class FutureController<T> {
val future = CompletableFuture<T>()
operator fun handleResult(value: T) {
future.complete(value)
}
operator fun handleException(exception: Throwable) {
future.completeExceptionally(exception)
}
}
Looks	like	Continuation<T>
Coroutine	builders	(prototype)
fun <T> async(
coroutine c: FutureController<T>.() -> Continuation<Unit>
): CompletableFuture<T> { … }
class FutureController<T> {
val future = CompletableFuture<T>()
operator fun handleResult(value: T) {
future.complete(value)
}
operator fun handleException(exception: Throwable) {
future.completeExceptionally(exception)
}
}
Something	that	takes	Continuation<T>
Coroutine	builders:	evolved
Coroutine	builders
fun <T> async(
c: suspend () -> T
): CompletableFuture<T> {
val controller = FutureController<T>()
c.startCoroutine(completion = controller)
return controller.future
}
Coroutine	builders
fun <T> async(
c: suspend () -> T
): CompletableFuture<T> {
val controller = FutureController<T>()
c.startCoroutine(completion = controller)
return controller.future
}
natural	signature
No	special	coroutine keyword
Coroutine	builders
fun <T> async(
c: suspend () -> T
): CompletableFuture<T> {
val controller = FutureController<T>()
c.startCoroutine(completion = controller)
return controller.future
}
Provided	by	standard	library
Coroutine	builders
fun <T> async(
c: suspend () -> T
): CompletableFuture<T> { … }
class FutureController<T> : Continuation<T> {
val future = CompletableFuture<T>()
override fun resume(value: T) {
future.complete(value)
}
override fun resumeWithException(exception: Throwable) {
future.completeExceptionally(exception)
}
}
Coroutine	builders
fun <T> async(
c: suspend () -> T
): CompletableFuture<T> { … }
class FutureController<T> : Continuation<T> {
val future = CompletableFuture<T>()
override fun resume(value: T) {
future.complete(value)
}
override fun resumeWithException(exception: Throwable) {
future.completeExceptionally(exception)
}
}
Serves	as	completion
continuation	for	coroutine
Bonus	features
Free	as	in	cheese
Arbitrary	suspending	calls
suspend fun <T> suspending(block: suspend () -> T): T =
suspendCoroutine { continuation ->
block.startCoroutine(completion = continuation)
}
Arbitrary	suspending	calls
suspend fun <T> suspending(block: suspend () -> T): T =
suspendCoroutine { continuation ->
block.startCoroutine(completion = continuation)
}
Arbitrary	suspending	calls
suspend fun <T> suspending(block: suspend () -> T): T =
suspendCoroutine { continuation ->
block.startCoroutine(completion = continuation)
}
Arbitrary	suspending	calls
suspend fun <T> suspending(block: suspend () -> T): T =
suspendCoroutine { continuation ->
block.startCoroutine(completion = continuation)
}
fun moreWork() = async {
println("Work started")
val str = work().await()
println("Work completed: $str")
}
Returns	CompletableFuture
Arbitrary	suspending	calls
suspend fun <T> suspending(block: suspend () -> T): T =
suspendCoroutine { continuation ->
block.startCoroutine(completion = continuation)
}
suspend fun moreWork(): T = suspending {
println("Work started")
val str = work().await()
println("Work completed: $str")
}
Arbitrary	suspending	calls
suspend fun <T> suspending(block: suspend () -> T): T =
suspendCoroutine { continuation ->
block.startCoroutine(completion = continuation)
}
suspend fun moreWork(): T = suspending {
println("Work started")
val str = work().await()
println("Work completed: $str")
}
Tail	suspend	invocation
Non-tail	(arbitrary)	suspend	invocation
Arbitrary	suspending	calls
suspend fun moreWork() {
println("Work started")
val str = work().await()
println("Work completed: $str")
}
Non-tail	(arbitrary)	suspend	invocation
Stackless vs	Stackful coroutines
The	crucial	distinction
Stackless vs	Stackful coroutines
Stackless Stackful
Restrictions Use	in	special ctx Use	anywhere
Implemented in C#,	Scala,	Kotlin, … Quasar, Javaflow,	…
Stackless vs	Stackful coroutines
Stackless Stackful
Restrictions Use	in	special ctx Use	anywhere
Implemented in C#,	Scala,	Kotlin, … Quasar, Javaflow,	…
Stackless vs	Stackful coroutines
Stackless Stackful
Restrictions Use	in	special ctx Use	anywhere
Implemented in C#,	Scala,	Kotlin, … Quasar, Javaflow,	…
Can suspend	in? suspend
functions
throws SuspendExecution /	
@Suspendable functions
Stackless vs	Stackful coroutines
Stackless Stackful
Restrictions Use	in	special ctx Use	anywhere
Implemented in C#,	Scala, … Kotlin,	Quasar, Javaflow,	…
Stackless vs	Stackful coroutines
Stackless Stackful
Restrictions Use	in	special ctx Use	anywhere
Implemented in C#,	Scala, Kotlin,	
Quasar, JavaFlow,	…
LISP,	Go,	…
Stackless vs	Stackful coroutines
Stackless Stackful
Restrictions Use	in	special ctx Use	anywhere
Implemented in C#,	Scala, … Kotlin,	Quasar, Javaflow,	…
False	
dichotomy
Async	vs	Suspending	functions
The	actual	difference
fun work() = async { … }
suspend fun work() { … }
fun work(): CompletableFuture<String> = async { … }
suspend fun work(): String { … }
In	Kotlin	you	have a	choice
fun workAsync(): CompletableFuture<String> = async { … }
suspend fun work(): String { … }
workAsync() VALID –>	produces	CompletableFuture<String>
workAsync().await() VALID –>	produces	String
concurrent	&	async	behavior
sequential	behavior
The	most	needed one,	yet	the	most	syntactically	
clumsy,	esp.	for	suspend-heavy	(CSP)	code	style	
The	problem	with	async
Kotlin	suspending	functions	
imitate	sequential behavior	
by	default	
Concurrency	is	hard
Concurrency	has	to	be	explicit
Composability
Making	those	legos click
Builders
fun <T> async(
c: suspend () -> T
): CompletableFuture<T> { … }
Builders
fun <T> async(
c: suspend () -> T
): ListenableFuture<T> { … }
Builders
fun <T> async(
c: suspend () -> T
): MyOwnFuture<T> { … }
Suspending	functions
fun <T> async(
c: suspend () -> T
): MyOwnFuture<T> { … }
suspend fun <T> CompletableFuture<T>.await(): T { … }
Suspending	functions
fun <T> async(
c: suspend () -> T
): MyOwnFuture<T> { … }
suspend fun <T> ListenableFuture<T>.await(): T { … }
Suspending	functions
fun <T> async(
c: suspend () -> T
): MyOwnFuture<T> { … }
suspend fun <T> MyOwnFuture<T>.await(): T { … }
Suspending	functions
fun <T> async(
c: suspend () -> T
): MyOwnFuture<T> { … }
suspend fun <T> MyOwnFuture<T>.await(): T { … }
fun moreWorkAsync() = async {
println("Work started")
val str = workAsync().await()
println("Work completed: $str")
}
All	combinations	need	to	compose
Composability:	evolved
• Kotlin	suspending	functions	are	composable by	default	
• Asynchronous use-case
• Define	asynchronous	suspending	functions	anywhere
• Use	them	inside	any	asynchronous	coroutine	builder
• Or	inside	other	suspending	functions
• generate/yield coroutines	are	synchronous
• Restricted	via	a	special	@RestrictsSuspension annotation
• Opt-in	to	define	synchronous	coroutines
Coroutine	context
The	last	piece	of	composability	puzzle
asyncUI (prototype)
asyncUI {
val image = await(loadImage(url))
myUI.updateImage(image)
}
Supposed	to	work	in	UI	thread
asyncUI (prototype)
asyncUI {
val image = await(loadImage(url))
myUI.updateImage(image)
}
A	special	coroutine	builder
asyncUI (prototype)
asyncUI {
val image = await(loadImage(url))
myUI.updateImage(image)
}
A	special	suspending	function in	its	scope
Composability	problem	
again!
asyncUI:	evolved
async(UI) {
val image = loadImageAsync(url).await()
myUI.updateImage(image)
}
asyncUI:	evolved
async(UI) {
val image = loadImageAsync(url).await()
myUI.updateImage(image)
}
Explicit	context	convention for	all	builders
Can	intercept continuation	to	
resume	in	the	appropriate	thread
The	actual	Continuation	interface
async(UI) {
val image = loadImageAsync(url).await()
myUI.updateImage(image)
}
interface Continuation<in T> {
val context: CoroutineContext
fun resume(value: T)
fun resumeWithException(exception: Throwable)
}
Is	used	to	transparently	lookup	an	
interceptor	for	resumes
The	actual	Continuation	interface
async(UI) {
val image = loadImageAsync(url).await()
myUI.updateImage(image)
}
interface Continuation<in T> {
val context: CoroutineContext
fun resume(value: T)
fun resumeWithException(exception: Throwable)
}
Does	not	have	to	be	aware	– receives	
intercepted	continuation	to	work	with
Thread-safety
A	million-dollar	quest	for	correctly-synchronized	(data-race	free)	code
A	need	for	happens-before	relation
fun moreWork() = async {
val list = ArrayList<String>()
val str = work().await()
list.add(str)
}
A	need	for	happens-before	relation
fun moreWork() = async {
val list = ArrayList<String>()
val str = work().await()
list.add(str)
}
One	thread
A	need	for	happens-before	relation
fun moreWork() = async {
val list = ArrayList<String>()
val str = work().await()
list.add(str)
}
One	thread
Suspends	/	resumes
A	need	for	happens-before	relation
fun moreWork() = async {
val list = ArrayList<String>()
val str = work().await()
list.add(str)
}
One	thread
Suspends	/	resumes
Another	thread
A	need	for	happens-before	relation
fun moreWork() = async {
val list = ArrayList<String>()
val str = work().await()
list.add(str)
}
One	thread
Suspends	/	resumes
Another	thread
Is	there	a	data	race?
Do	we	need	volatile	when	spilling	
locals	to	a	state	machine?
A	need	for	happens-before	relation
fun moreWork() = async {
val list = ArrayList<String>()
val str = work().await()
list.add(str)
}
There	is	no	data	race	here!	
await establishes	happens-before	relation
happens-before
Challenges
If	it	only	was	all	that	simple…
Thread	confinement	vs	coroutines
fun moreWork() = async {
synchronized(monitor) {
val str = work().await()
}
}
Thread	confinement	vs	coroutines
fun moreWork() = async {
synchronized(monitor) {
val str = work().await()
}
}
MONITORENTER in	one	thread
Suspends	/	resumes
MONITOREXIT in	another	thread
IllegalMonitorStateException
Thread	confinement	vs	coroutines
• Monitors
• Locks	(j.u.c.l.ReentrantLock)
• Thread-locals
• …
• Thread.currentThread()
A	CoroutineContext is	a	map	of	
coroutine-local	elements	as	replacement
Stack	traces	in	exceptions
Stack	traces	in	exceptions
suspend fun moreWork() {
work()
}
suspend fun work() {
someAsyncOp().await()
throw Exception()
}
stack
moreWork
Stack	traces	in	exceptions
suspend fun moreWork() {
work()
}
suspend fun work() {
someAsyncOp().await()
throw Exception()
}
stack
moreWork
work
Stack	traces	in	exceptions
suspend fun moreWork() {
work()
}
suspend fun work() {
someAsyncOp().await()
throw Exception()
}
stack
moreWork
work
await
Stack	traces	in	exceptions
suspend fun moreWork() {
work()
}
suspend fun work() {
someAsyncOp().await()
throw Exception()
}
stack
moreWork
work
Work$StateMachine :
Continuation
----------
fun resume(v)
Stack	traces	in	exceptions
suspend fun moreWork() {
work()
}
suspend fun work() {
someAsyncOp().await()
throw Exception()
}
stack
Work$StateMachine.resume
work
Stack	traces	in	exceptions
suspend fun moreWork() {
work()
}
suspend fun work() {
someAsyncOp().await()
throw Exception()
}
JVM	stack
Work$StateMachine.resume
work
Stack	traces	in	exceptions
suspend fun moreWork() {
work()
}
suspend fun work() {
someAsyncOp().await()
throw Exception()
}
JVM	stack
Work$StateMachine.resume
work
Coroutine	stack
moreWork
work
Stack	traces	in	exceptions
suspend fun moreWork() {
work()
}
suspend fun work() {
someAsyncOp().await()
throw Exception()
}
JVM	stack
Work$StateMachine.resume
work
Coroutine	stack
moreWork
work
Gets	thrown
Stack	traces	in	exceptions
suspend fun moreWork() {
work()
}
suspend fun work() {
someAsyncOp().await()
throw Exception()
}
JVM	stack
Work$StateMachine.resume
work
Coroutine	stack
moreWork
work
Gets	thrown User	wants
Library	evolution
Going	beyond	the	language	&	stdlib
Library	evolution:	already	there
• Communication	&	synchronization	primitives
• Job:	A	completable &	cancellable	entity	to	represent	a	coroutine
• Deferred:	A	future	with	suspend fun	await (and	no thread-blocking	methods)
• Mutex:	with	suspend fun	lock
• Channel:	SendChannel &	ReceiveChannel
• RendezvousChannel – synchronous	rendezvous
• ArrayChannel – fixed	size	buffer
• LinkedListChannel – unlimited	buffer
• ConflatedChannel – only	the	most	recent	sent	element	is	kept
• BroadcastChannel:	multiple	subscribes,	all	receive
Library	evolution:	already	there
• Coroutine	builders
• launch (fire	&	forget,	returns	a	Job)
• async (returns	Deferred)
• future	(integration	with	CompletableFuture &	ListenableFuture)
• runBlocking (to	explicitly	delimit	code	that	blocks	a	thread)
• actor	/ produce	(consume	&	produce	messages	over	channels)
• publish (integration	with	reactive	streams,	returns	Publisher)
• rxCompletable,	rxSingle,	rxObservable,	rxFlowable (RxJava 1/2)
Library	evolution:	already	there
• Top-level	functions	
• select expression	to	await	multiple	events	for	full	CSP-style	programming
• delay	for	time-based	logic	in	coroutines	
• Extensions
• await for	all	kinds	of	futures	(JDK,	Guava,	RxJava)
• aRead,	aWrite,	etc for	AsynchronousXxxChannel in	NIO
• Cancellation	&	job	(coroutine/actor)	hierarchies
• withTimeout for	a	composable way	for	any	suspend	function	run	w/timeout
Library	evolution:	WIP
• Serialization	/	migration	of	coroutines
• Migrating	libraries	to	Kotlin/JS	&	Kotlin/Native	(lang support	– done)
• Full	scope	of	pipelining	operators	on	channels	(filter,	map,	etc)
• Optimizations	for	single-producer	and/or	single-consumer	cases
• Allow	3rd party	primitives	to	participate	in	select (alternatives)
• ByteChannel for	suspendable IO	(http	client/server,	websocket,	etc)
• See	also	ktor.io
A	closing	note	on	terminology
• We	don’t	use	the	term	fiber/strand/green	threads/…
• The	term	coroutine works	just	as	well
• ”Fibers	describe	essentially	the	same	concept	as	coroutines”	©	Wikipedia
Kotlin	Coroutines	are	very light-weight	threads
Wrap	up
Let’s	call	it	a	day
Experimental	status	of	coroutines
• This	design	is	new and	unlike	mainstream
• For	some	very	good	reasons
• We	want	community	to	try	it	for	real
• So	we	released	it	as	an	experimental feature
• We	guarantee	backwards	compatibility
• Old	code	compiled	with	coroutines	continues	to	work
• We	reserve	the	right	to	break	forward	compatibility
• We	may	add	things	so	new	code	may	not	run	w/old	RT
• Design	will	be	finalized	at	a	later	point
• Old	code	will	continue	to	work	via	support	library
• Migration	aids	to	the	final	design	will	be	provided
opt-in	flag
Thank	you
Any	questions?
Slides	are	available	at	www.slideshare.net/elizarov
email	elizarov at	gmail
relizarov

More Related Content

PDF
Deep dive into Coroutines on JVM @ KotlinConf 2017
PDF
Introduction to Coroutines @ KotlinConf 2017
PDF
Kotlin Coroutines in Practice @ KotlinConf 2018
PPTX
Coroutines in Kotlin
PDF
Introduction to kotlin coroutines
PDF
Kotlin for Android Development
PDF
Introduction to Kotlin coroutines
PDF
Coroutines for Kotlin Multiplatform in Practise
Deep dive into Coroutines on JVM @ KotlinConf 2017
Introduction to Coroutines @ KotlinConf 2017
Kotlin Coroutines in Practice @ KotlinConf 2018
Coroutines in Kotlin
Introduction to kotlin coroutines
Kotlin for Android Development
Introduction to Kotlin coroutines
Coroutines for Kotlin Multiplatform in Practise

What's hot (20)

PDF
Try Jetpack Compose
PPT
Android | Android Activity Launch Modes and Tasks | Gonçalo Silva
PPTX
Angular modules in depth
PDF
A quick and fast intro to Kotlin
PDF
Angular - Chapter 5 - Directives
PPTX
Broadcast Receiver
PDF
Towards Functional Programming through Hexagonal Architecture
PDF
Declarative UIs with Jetpack Compose
PPTX
Introduction to Koltin for Android Part I
PPTX
Kotlin InDepth Tutorial for beginners 2022
PDF
Angular 2 observables
PDF
Lessons Learned from Building 100+ C++/Qt/QML Devices
 
PPTX
Core java complete ppt(note)
PDF
Angular and The Case for RxJS
PDF
Kotlin - Better Java
PPTX
Introduction to Kotlin Language and its application to Android platform
PPTX
Kotlin
PDF
Kotlin Coroutines. Flow is coming
PDF
ES6 presentation
PPT
Try Jetpack Compose
Android | Android Activity Launch Modes and Tasks | Gonçalo Silva
Angular modules in depth
A quick and fast intro to Kotlin
Angular - Chapter 5 - Directives
Broadcast Receiver
Towards Functional Programming through Hexagonal Architecture
Declarative UIs with Jetpack Compose
Introduction to Koltin for Android Part I
Kotlin InDepth Tutorial for beginners 2022
Angular 2 observables
Lessons Learned from Building 100+ C++/Qt/QML Devices
 
Core java complete ppt(note)
Angular and The Case for RxJS
Kotlin - Better Java
Introduction to Kotlin Language and its application to Android platform
Kotlin
Kotlin Coroutines. Flow is coming
ES6 presentation
Ad

Similar to Kotlin Coroutines Reloaded (20)

PDF
JVMLS 2016. Coroutines in Kotlin
PDF
Coroutines in Kotlin. In-depth review
PDF
Coroutines in Kotlin. UA Mobile 2017.
PDF
Kotlin coroutine - behind the scenes
PPTX
NDC Sydney 2019 - Async Demystified -- Karel Zikmund
PPTX
Concurrent Application Development using Scala
PPTX
.NET Core Summer event 2019 in Brno, CZ - Async demystified -- Karel Zikmund
PDF
Dip into Coroutines - KTUG Munich 202303
PPTX
01 Introduction to Kotlin - Programming in Kotlin.pptx
PPTX
Introduction to Kotlin.pptx
PDF
Kotlin coroutine - the next step for RxJava developer?
PDF
Kotlin - Coroutine
PDF
Asynchronní programování
PDF
Advanced patterns in asynchronous programming
PDF
yield and return (poor English ver)
PDF
Current State of Coroutines
PPTX
Property based testing
PPTX
Namespaces
PDF
Kotlin : Advanced Tricks - Ubiratan Soares
PDF
Python Coroutines, Present and Future
JVMLS 2016. Coroutines in Kotlin
Coroutines in Kotlin. In-depth review
Coroutines in Kotlin. UA Mobile 2017.
Kotlin coroutine - behind the scenes
NDC Sydney 2019 - Async Demystified -- Karel Zikmund
Concurrent Application Development using Scala
.NET Core Summer event 2019 in Brno, CZ - Async demystified -- Karel Zikmund
Dip into Coroutines - KTUG Munich 202303
01 Introduction to Kotlin - Programming in Kotlin.pptx
Introduction to Kotlin.pptx
Kotlin coroutine - the next step for RxJava developer?
Kotlin - Coroutine
Asynchronní programování
Advanced patterns in asynchronous programming
yield and return (poor English ver)
Current State of Coroutines
Property based testing
Namespaces
Kotlin : Advanced Tricks - Ubiratan Soares
Python Coroutines, Present and Future
Ad

More from Roman Elizarov (19)

PDF
Fresh Async with Kotlin @ QConSF 2017
PDF
Scale Up with Lock-Free Algorithms @ JavaOne
PDF
Lock-free algorithms for Kotlin Coroutines
PPTX
Non blocking programming and waiting
PDF
ACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems Review
PDF
Многопоточное Программирование - Теория и Практика
PDF
Wait for your fortune without Blocking!
PDF
ACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems Review
PDF
ACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems Review
PDF
Why GC is eating all my CPU?
PDF
Многопоточные Алгоритмы (для BitByte 2014)
PDF
Теоретический минимум для понимания Java Memory Model (для JPoint 2014)
PPTX
DIY Java Profiling
PDF
ACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems Review
PPTX
Java Serialization Facts and Fallacies
PPTX
Millions quotes per second in pure java
PPTX
ACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems Review
PPTX
The theory of concurrent programming for a seasoned programmer
PPTX
Пишем самый быстрый хеш для кэширования данных
Fresh Async with Kotlin @ QConSF 2017
Scale Up with Lock-Free Algorithms @ JavaOne
Lock-free algorithms for Kotlin Coroutines
Non blocking programming and waiting
ACM ICPC 2016 NEERC (Northeastern European Regional Contest) Problems Review
Многопоточное Программирование - Теория и Практика
Wait for your fortune without Blocking!
ACM ICPC 2015 NEERC (Northeastern European Regional Contest) Problems Review
ACM ICPC 2014 NEERC (Northeastern European Regional Contest) Problems Review
Why GC is eating all my CPU?
Многопоточные Алгоритмы (для BitByte 2014)
Теоретический минимум для понимания Java Memory Model (для JPoint 2014)
DIY Java Profiling
ACM ICPC 2013 NEERC (Northeastern European Regional Contest) Problems Review
Java Serialization Facts and Fallacies
Millions quotes per second in pure java
ACM ICPC 2012 NEERC (Northeastern European Regional Contest) Problems Review
The theory of concurrent programming for a seasoned programmer
Пишем самый быстрый хеш для кэширования данных

Recently uploaded (20)

PDF
NewMind AI Weekly Chronicles - August'25 Week I
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PPTX
Spectroscopy.pptx food analysis technology
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PPTX
Cloud computing and distributed systems.
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PPT
Teaching material agriculture food technology
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
cuic standard and advanced reporting.pdf
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
NewMind AI Weekly Chronicles - August'25 Week I
Digital-Transformation-Roadmap-for-Companies.pptx
Spectroscopy.pptx food analysis technology
Diabetes mellitus diagnosis method based random forest with bat algorithm
Reach Out and Touch Someone: Haptics and Empathic Computing
Cloud computing and distributed systems.
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Teaching material agriculture food technology
MIND Revenue Release Quarter 2 2025 Press Release
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Per capita expenditure prediction using model stacking based on satellite ima...
The Rise and Fall of 3GPP – Time for a Sabbatical?
Programs and apps: productivity, graphics, security and other tools
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
cuic standard and advanced reporting.pdf
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
How UI/UX Design Impacts User Retention in Mobile Apps.pdf

Kotlin Coroutines Reloaded