Introduce Kotlin Coroutine(@CA.kt_2017/06)

Daec7e5cd5fae384eda88037d937343b?s=47 AAkira
June 15, 2017

Introduce Kotlin Coroutine(@CA.kt_2017/06)

CA.kt @CyberAgent
Introduce Kotlin Coroutine
https://cyberagent.connpass.com/event/57963/

Daec7e5cd5fae384eda88037d937343b?s=128

AAkira

June 15, 2017
Tweet

Transcript

  1. 2.

    $ whois private lateinit var aakira: User data class User(val

    name: String, val twitterId: String, val githubId: String, val company: String) println("Name : ${aakira.name}") println("Twitter Id : ${aakira.twitterId}") println("Github Id : ${aakira.githubId}") println("Company : ${aakira.company}")
  2. 3.

    @_a_akira AAkira CyberAgent, Inc. Akira Aratani private lateinit var aakira

    : User data class User(val name: String, val twitterId: String, val githubId: String, val company: String) print("Name : ${aakira.name}”) println("Github Id : ${aakira.githubId}") print("Twitter Id : ${aakira.twitterId}") println("Company : ${aakira.company}") $ whois
  3. 4.

    @_a_akira AAkira CyberAgent, Inc. Akira Aratani private lateinit var aakira

    : User data class User(val name: String, val twitterId: String, val githubId: String, val company: String) print("Name : ${aakira.name}”) println("Github Id : ${aakira.githubId}") print("Twitter Id : ${aakira.twitterId}") println("Company : ${aakira.company}") $ whois ,PUMJOॿ૸ಡຊ΋ॻ͍ͨIUUQTHPPHM"$K')
  4. 5.

    About • 生放送配信プラットフォーム ≠ AbemaTV • 最近 アプリを縦化! FRESH! AndroidアプリのUI/UX :

    https://developers.cyberagent.co.jp/blog/archives/7177 • Full Kotlin • 使ってるLibraryは大体最新
 (Kotlin1.1, Rx2, Dagger2, Retrofit2, Ok3, ExoPlayer2 etc) • もちろんコルーチンも一部で導入済み
  5. 6.

    私とKotlin M1 2012-04-12 M11 2015-03-19 M14 2015-10-01 1.0-beta4 2015-12-22 M13

    2015-09-16 1.0 2016-02-16 1.0-RC 2016-02-04 2016-01-21 Release 2015-04 開発開始 kotlin FRESH 1.1 2017-03-01 2017-05-15 Renewal
  6. 8.

    About Coroutine • Kotlin 1.1で導入された非同期プログラミングのための機能  ≠ Thread : 特定のスレッドに属していないので、再開先は別のスレッドで動作可能 •

    1.1ではまだExperimentalなので、仕様変更の可能性あり • 言語機能ではなく、ライブラリとして提供されている
  7. 9.

    Introduce Coroutine def kotlinCoroutinesVersion = "0.15" // for core compile

    “org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutinesVersion” // for JDK8 compile “org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$kotlinCoroutinesVersion” // for Asynchronous IO on JDK7+ compile “org.jetbrains.kotlinx:kotlinx-coroutines-nio:$kotlinCoroutinesVersion" // for RxJava2 compile “org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlinCoroutinesVersion" // for Android compile “org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutinesVersion" // for Swing compile “org.jetbrains.kotlinx:kotlinx-coroutines-swing:$kotlinCoroutinesVersion" // for JavaFX compile “org.jetbrains.kotlinx:kotlinx-coroutines-javafx:$kotlinCoroutinesVersion"
  8. 10.

    Introduce Coroutine // for core compile “org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutinesVersion” // for JDK8

    compile “org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$kotlinCoroutinesVersion” // for Asynchronous IO on JDK7+ compile “org.jetbrains.kotlinx:kotlinx-coroutines-nio:$kotlinCoroutinesVersion" // for RxJava2 compile “org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlinCoroutinesVersion" // for Android compile “org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutinesVersion" // for Swing compile “org.jetbrains.kotlinx:kotlinx-coroutines-swing:$kotlinCoroutinesVersion" // for JavaFX compile “org.jetbrains.kotlinx:kotlinx-coroutines-javafx:$kotlinCoroutinesVersion" Ұൠతͳ"OESPJEͰ։ൃͰඞཁͳϥΠϒϥϦ
  9. 11.

    Elements of coroutine • Suspending functions • Coroutine builders (Suspending

    lambda) • Coroutine dispatchers (Coroutine context)
  10. 15.

    Suspending functions delayもsuspend関数 suspend fun delay(time: Long, unit: TimeUnit =

    TimeUnit.MILLISECONDS) { require(time >= 0) { "Delay time $time cannot be negative" } if (time <= 0) return // don't delay return suspendCancellableCoroutine sc@ { cont: CancellableContinuation<Unit> -> val delay = cont.context[ContinuationInterceptor] as? Delay if (delay != null) delay.scheduleResumeAfterDelay(time, unit, cont) else cont.cancelFutureOnCompletion( scheduledExecutor.schedule(ResumeRunnable(cont), time, unit)) } }
  11. 16.

    Suspending functions suspend fun hoge(): Int { delay(10, TimeUnit.SECONDS) return

    100 } hogeもsuspend関数なのでdelayを呼び出せる
  12. 18.

    Suspending functions 10秒後に “CA.kt” と出力される foo({ delay(10, TimeUnit.SECONDS) "CA.kt" })

    fun foo(bar: suspend () -> String) { launch(CommonPool) { println(bar.invoke()) } }
  13. 19.

    Suspending functions foo({ delay(10, TimeUnit.SECONDS) "CA.kt" }) fun foo(bar: suspend

    () -> String) { launch(CommonPool) { println(bar.invoke()) } }
  14. 22.

    Coroutine builders Name Result Scope Description launch Job CoroutineScope Launches

    coroutine that does not have any result async Deferred CoroutineScope Returns a single value with the future result produce ProducerJob ProducerScope Produces a stream of elements actor ActorJob ActorScope Processes a stream of messages runBlocking T CoroutineScope Blocks the thread while the coroutine runs IUUQTHJUIVCDPN,PUMJOLPUMJOYDPSPVUJOFT
  15. 25.

    async 結果を返すコルーチンを作る public fun <T> async( context: CoroutineContext, start: CoroutineStart

    = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> T ): Deferred<T> {
  16. 26.

    launchとasyncの違い • launchはJobを返す • asyncはDeferred<T>を返す • DeferredはJobのinterface public interface Deferred<out

    T> : Job { val isCompletedExceptionally: Boolean val isCancelled: Boolean public suspend fun await(): T public fun <R> registerSelectAwait(select: SelectInstance<R>, block: suspend (T) -> R) public fun getCompleted(): T }
  17. 27.

    Others (Coroutine builders) • 入門としてはlaunchとasyncが使えれば問題ない • produce, actorはgoroutineのようなChannelの概念がある
 produce: sender,

    actor: receiver • runBlockingはその名の通りスレッドを止めて動作する cf: https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md
  18. 29.

    Coroutine dispatchers Name Description CommonPool Confines coroutine execution to a

    shared pool of threads newSingleThreadContext Create new single-threaded coroutine context newFixedThreadPoolContext Creates new thread pool of a fixed size Executor.asCoroutineDispatcher Extension to convert any executor Unconfined Does not confine coroutine execution in any way IUUQTHJUIVCDPN,PUMJOLPUMJOYDPSPVUJOFT
  19. 33.

    asCoroutineDispatcher java.util.concurrentのExecutorをCoroutine Contextに変換出来る class MyCoroutineExecutor : Executor { override fun

    execute(command: Runnable?) { } } val myCoroutineExecutor = MyCoroutineExecutor() launch(myCoroutineExecutor.asCoroutineDispatcher()) { }
  20. 39.

    さっき読めなかったやつ foo({ delay(10, TimeUnit.SECONDS) "CA.kt" }) fun foo(bar: suspend ()

    -> String) { launch(CommonPool) { println(bar.invoke()) } } 引数に取ったbar suspend関数を実行するコルーチンを
 良い感じのスレッドで実行して結果を出力
  21. 41.

    Example 1-1 fun main() { println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) {

    println("----1---- : ${Thread.currentThread().name}") println(foo()) println("----2---- : ${Thread.currentThread().name}") } println("----3---- : ${Thread.currentThread().name}”) }
  22. 42.

    Example 1-1 ----0---- : main ----3---- : main ----1---- :

    ForkJoinPool.commonPool-worker-1
 ---foo--- : ForkJoinPool.commonPool-worker-1 CA.kt ----2---- : ForkJoinPool.commonPool-worker-1 fun main() { println("----0----- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1----- : ${Thread.currentThread().name}") println(foo()) println("----2----- : ${Thread.currentThread().name}") } println("----3----- : ${Thread.currentThread().name}”) }
  23. 43.

    Example 1-1 ----0---- : main ----3---- : main ----1---- :

    ForkJoinPool.commonPool-worker-1
 ---foo--- : ForkJoinPool.commonPool-worker-1 CA.kt ----2---- : ForkJoinPool.commonPool-worker-1 ※ Threadの数字は実行環境によって変わるので、気にしなくても大丈夫です
  24. 44.

    Example 1-2 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") println(foo.await()) println("----3---- : ${Thread.currentThread().name}") } println("----4---- : ${Thread.currentThread().name}")
  25. 45.

    Example 1-2 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") println(foo.await()) println("----3---- : ${Thread.currentThread().name}") } println("----4---- : ${Thread.currentThread().name}") Deferred<T>.await() => 実行を中断して値を返すsuspend関数
  26. 46.

    Example 1-2 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") println(foo.await()) println("----3---- : ${Thread.currentThread().name}") } println("----4---- : ${Thread.currentThread().name}") ----0---- : main ----4---- : main ----1---- : ForkJoinPool.commonPool-worker-1 ----2---- : ForkJoinPool.commonPool-worker-1
 ---foo--- : ForkJoinPool.commonPool-worker-1 CA.kt ----3---- : ForkJoinPool.commonPool-worker-1
  27. 47.

    Example 1-3 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") foo.join() println("----3---- : ${Thread.currentThread().name}") println(foo.getCompleted()) println("----4---- : ${Thread.currentThread().name}") } println("----5---- : ${Thread.currentThread().name}")
  28. 48.

    Example 1-3 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") foo.join() println("----3---- : ${Thread.currentThread().name}") println(foo.getCompleted()) println("----4---- : ${Thread.currentThread().name}") } println("----5---- : ${Thread.currentThread().name}") Job.join() => await同様coroutineの実行完了まで待つが戻り値が無い
  29. 49.

    Example 1-3 ----0---- : main ----5---- : main ----1---- :

    ForkJoinPool.commonPool-worker-1 ----2---- : ForkJoinPool.commonPool-worker-1 ---foo--- : ForkJoinPool.commonPool-worker-2 ----3---- : ForkJoinPool.commonPool-worker-1 CA.kt ----4---- : ForkJoinPool.commonPool-worker-1 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}") val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") foo.join() println("----3---- : ${Thread.currentThread().name}") println(foo.getCompleted()) println("----4---- : ${Thread.currentThread().name}") } println("----5---- : ${Thread.currentThread().name}")
  30. 50.

    Example 2 suspend fun foo(): String { println("---foo--- : ${Thread.currentThread().name}")

    delay(6, TimeUnit.SECONDS) return "foo" } suspend fun bar(): String { println("---bar--- : ${Thread.currentThread().name}") delay(3, TimeUnit.SECONDS) return "bar" }
  31. 51.

    Example 2-1 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() }.await() println("----2---- : ${Thread.currentThread().name}") val bar = async(CommonPool) { bar() }.await() println("----3---- : ${Thread.currentThread().name}") println(foo) println("----4---- : ${Thread.currentThread().name}") println(bar) println("----5---- : ${Thread.currentThread().name}") } println("----6---- : ${Thread.currentThread().name}")
  32. 52.

    Example 2-1 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() }.await() println("----2---- : ${Thread.currentThread().name}") val bar = async(CommonPool) { bar() }.await() println("----3---- : ${Thread.currentThread().name}") println(foo) println("----4---- : ${Thread.currentThread().name}") println(bar) println("----5---- : ${Thread.currentThread().name}") } println("----6---- : ${Thread.currentThread().name}") ----0---- : main ----6---- : main ----1---- : ForkJoinPool.commonPool-worker-1 ---foo--- : ForkJoinPool.commonPool-worker-2 ----2---- : ForkJoinPool.commonPool-worker-1 ---bar--- : ForkJoinPool.commonPool-worker-1 ----3---- : ForkJoinPool.commonPool-worker-1 foo ----4---- : ForkJoinPool.commonPool-worker-1 bar ----5---- : ForkJoinPool.commonPool-worker-1
  33. 53.

    Example 2-1 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() }.await() println("----2---- : ${Thread.currentThread().name}") val bar = async(CommonPool) { bar() }.await() println("----3---- : ${Thread.currentThread().name}") println(foo) println("----4---- : ${Thread.currentThread().name}") println(bar) println("----5---- : ${Thread.currentThread().name}") } println("----6---- : ${Thread.currentThread().name}") ----0---- : main ----6---- : main ----1---- : ForkJoinPool.commonPool-worker-1 ---foo--- : ForkJoinPool.commonPool-worker-1 ----2---- : ForkJoinPool.commonPool-worker-1 ---bar--- : ForkJoinPool.commonPool-worker-1 ----3---- : ForkJoinPool.commonPool-worker-1 foo ----4---- : ForkJoinPool.commonPool-worker-1 bar ----5---- : ForkJoinPool.commonPool-worker-1 ඵ͔͔Δ ௚ྻ࣮ߦ
  34. 54.

    Example 2-2 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") val bar = async(CommonPool) { bar() } println("----3---- : ${Thread.currentThread().name}") println(foo.await()) println("----4---- : ${Thread.currentThread().name}") println(bar.await()) println("----5---- : ${Thread.currentThread().name}") } println("----6---- : ${Thread.currentThread().name}")
  35. 55.

    Example 2-2 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") val bar = async(CommonPool) { bar() } println("----3---- : ${Thread.currentThread().name}") println(foo.await()) println("----4---- : ${Thread.currentThread().name}") println(bar.await()) println("----5---- : ${Thread.currentThread().name}") } println("----6---- : ${Thread.currentThread().name}") ----0---- : main ----6---- : main ----1---- : ForkJoinPool.commonPool-worker-1 ----2---- : ForkJoinPool.commonPool-worker-1 ----3---- : ForkJoinPool.commonPool-worker-1 ---foo--- : ForkJoinPool.commonPool-worker-2 ---bar--- : ForkJoinPool.commonPool-worker-1 foo ----4---- : ForkJoinPool.commonPool-worker-1 bar ----5---- : ForkJoinPool.commonPool-worker-1
  36. 56.

    Example 2-2 println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}")

    val foo = async(CommonPool) { foo() } println("----2---- : ${Thread.currentThread().name}") val bar = async(CommonPool) { bar() } println("----3---- : ${Thread.currentThread().name}") println(foo.await()) println("----4---- : ${Thread.currentThread().name}") println(bar.await()) println("----5---- : ${Thread.currentThread().name}") } println("----6---- : ${Thread.currentThread().name}") ----0---- : main ----6---- : main ----1---- : ForkJoinPool.commonPool-worker-1 ----2---- : ForkJoinPool.commonPool-worker-1 ----3---- : ForkJoinPool.commonPool-worker-1 ---foo--- : ForkJoinPool.commonPool-worker-2 ---bar--- : ForkJoinPool.commonPool-worker-1 foo ----4---- : ForkJoinPool.commonPool-worker-1 bar ----5---- : ForkJoinPool.commonPool-worker-1 ඵͰऴΘΔ ฒྻॲཧ
  37. 57.

    Example 3 @Android Clickしたら3秒後にtext viewにCA.ktをsetする val button: Button val textView:

    TextView suspend fun foo(): String { delay(3, TimeUnit.SECONDS) return "CA.kt" } fun main() {
 button.setOnClickListener { launch(CommonPool) { textView.text = foo() } } }
  38. 58.
  39. 59.

    Example 3 @Android Main thread以外でViewの更新は出来ない val button: Button val textView:

    TextView suspend fun foo(): String { delay(3, TimeUnit.SECONDS) return "CA.kt" } fun main() {
 button.setOnClickListener { launch(CommonPool) { textView.text = foo() } } }
  40. 60.

    Example 3 @Android // for core compile “org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutinesVersion” // for

    JDK8 compile “org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$kotlinCoroutinesVersion” // for Asynchronous IO on JDK7+ compile “org.jetbrains.kotlinx:kotlinx-coroutines-nio:$kotlinCoroutinesVersion" // for RxJava2 compile “org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlinCoroutinesVersion" // for Android compile “org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutinesVersion" // for Swing compile “org.jetbrains.kotlinx:kotlinx-coroutines-swing:$kotlinCoroutinesVersion" // for JavaFX compile “org.jetbrains.kotlinx:kotlinx-coroutines-javafx:$kotlinCoroutinesVersion" "OESPJE༻ʹ$PSPVUJOFEJTQBUDIFS͕༻ҙ͞Ε͍ͯΔ
  41. 61.

    Example 3 @Android val UI = HandlerContext(Handler(Looper.getMainLooper()), "UI") fun Handler.asCoroutineDispatcher()

    = HandlerContext(this) public class HandlerContext(private val handler: Handler, private val name: String? = null) : CoroutineDispatcher(), Delay { override fun dispatch(context: CoroutineContext, block: Runnable) { handler.post(block) } override fun scheduleResumeAfterDelay(time: Long, unit: TimeUnit, continuation: CancellableContinuation<Unit>) { handler.postDelayed({ with(continuation) { resumeUndispatched(Unit) } }, unit.toMillis(time)) } override fun invokeOnTimeout(time: Long, unit: TimeUnit, block: Runnable): DisposableHandle { handler.postDelayed(block, unit.toMillis(time)) return object : DisposableHandle { override fun dispose() { handler.removeCallbacks(block) } } } override fun toString() = name ?: handler.toString() override fun equals(other: Any?): Boolean = other is HandlerContext && other.handler === handler override fun hashCode(): Int = System.identityHashCode(handler) }
  42. 62.

    Example 3 @Android val button: Button val textView: TextView suspend

    fun foo(): String { delay(3, TimeUnit.SECONDS) return "CA.kt" } fun main() {
 button.setOnClickListener { launch(UI) { textView.text = foo() } } } Coroutine contextの引数をUIに置き換えると想定通りの動作
  43. 63.

    Example 4 @RxJava RxJavaのBehaviorProcessorにある値を取得して出力 val fooProcessor = BehaviorProcessor.createDefault<String>("CA.kt") println("----0---- :

    ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}") val foo = async(CommonPool) { fooProcessor .doOnNext { println("----2---- : ${Thread.currentThread().name}") } .awaitFirst() } println("----3---- : ${Thread.currentThread().name}") println(foo.await()) println("----4---- : ${Thread.currentThread().name}”) } println("----5---- : ${Thread.currentThread().name}")
  44. 64.

    Example 4 @RxJava awaitFirst() => Rxのstreamからthreadをblockせずに
         値をとってくるsuspend関数 val fooProcessor

    = BehaviorProcessor.createDefault<String>("CA.kt") println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}") val foo = async(CommonPool) { fooProcessor .doOnNext { println("----2---- : ${Thread.currentThread().name}") } .awaitFirst() } println("----3---- : ${Thread.currentThread().name}") println(foo.await()) println("----4---- : ${Thread.currentThread().name}") } println("----5---- : ${Thread.currentThread().name}")
  45. 65.

    Example 4 @RxJava ----0---- : main ----5---- : main ----1----

    : ForkJoinPool.commonPool-worker-1 ----3---- : ForkJoinPool.commonPool-worker-1 ----2---- : ForkJoinPool.commonPool-worker-2 CA.kt ----4---- : ForkJoinPool.commonPool-worker-1 val fooProcessor = BehaviorProcessor.createDefault<String>("CA.kt") println("----0---- : ${Thread.currentThread().name}") launch(CommonPool) { println("----1---- : ${Thread.currentThread().name}") val foo = async(CommonPool) { fooProcessor .doOnNext { println("----2---- : ${Thread.currentThread().name}") } .awaitFirst() } println("----3---- : ${Thread.currentThread().name}") println(foo.await()) println("----4---- : ${Thread.currentThread().name}”) } println("----5---- : ${Thread.currentThread().name}")
  46. 69.

    Resource management and GC fun sequenceOfLines(fileName: String) = buildSequence<String> {

    BufferedReader(FileReader(fileName)).use { while (true) { yield(it.readLine() ?: break) } } } fun main(args: Array<String>) { sequenceOfLines("examples/sequence/sequenceOfLines.kt") .forEach(::println) } DGIUUQTHJUIVCDPN,PUMJOLPUMJODPSPVUJOFT
  47. 71.

    Bytecode • 2つの中断があるコルーチン • 状態 A. 1つ目の中断の前 B. 1つ目の中断後 C.

    2つ目の中断後 val a = a() val y = foo(a).await() // suspension point #1 b() val z = bar(a, y).await() // suspension point #2 c(z)
  48. 72.

    class <anonymous_for_state_machine> extends CoroutineImpl<...> implements Continuation<Object> { // The current

    state of the state machine int label = 0 // local variables of the coroutine A a = null Y y = null void resume(Object data) { if (label == 0) goto L0 if (label == 1) goto L1 if (label == 2) goto L2 else throw IllegalStateException() L0: // data is expected to be `null` at this invocation a = a() label = 1 data = foo(a).await(this) // 'this' is passed as a continuation if (data == COROUTINE_SUSPENDED) return // return if await had suspended execution L1: // external code has resumed this coroutine passing the result of .await() as data y = (Y) data b() label = 2 data = bar(a, y).await(this) // 'this' is passed as a continuation if (data == COROUTINE_SUSPENDED) return // return if await had suspended execution L2: // external code has resumed this coroutine passing the result of .await() as data Z z = (Z) data c(z) label = -1 // No more steps are allowed return } }
  49. 73.

    class <anonymous_for_state_machine> extends CoroutineImpl<...> implements Continuation<Object> { // The current

    state of the state machine int label = 0 // local variables of the coroutine A a = null Y y = null void resume(Object data) { if (label == 0) goto L0 if (label == 1) goto L1 if (label == 2) goto L2 else throw IllegalStateException() L0: // data is expected to be `null` at this invocation a = a() label = 1 data = foo(a).await(this) // 'this' is passed as a continuation if (data == COROUTINE_SUSPENDED) return // return if await had suspended execution L1: // external code has resumed this coroutine passing the result of .await() as data y = (Y) data b() label = 2 data = bar(a, y).await(this) // 'this' is passed as a continuation if (data == COROUTINE_SUSPENDED) return // return if await had suspended execution L2: // external code has resumed this coroutine passing the result of .await() as data Z z = (Z) data c(z) label = -1 // No more steps are allowed return } }
  50. 74.

    class <anonymous_for_state_machine> extends CoroutineImpl<...> implements Continuation<Object> { // The current

    state of the state machine int label = 0 // local variables of the coroutine A a = null Y y = null void resume(Object data) { if (label == 0) goto L0 if (label == 1) goto L1 if (label == 2) goto L2 else throw IllegalStateException() L0: // data is expected to be `null` at this invocation a = a() label = 1 data = foo(a).await(this) // 'this' is passed as a continuation if (data == COROUTINE_SUSPENDED) return // return if await had suspended execution L1: // external code has resumed this coroutine passing the result of .await() as data y = (Y) data b() label = 2 data = bar(a, y).await(this) // 'this' is passed as a continuation if (data == COROUTINE_SUSPENDED) return // return if await had suspended execution L2: // external code has resumed this coroutine passing the result of .await() as data Z z = (Z) data c(z) label = -1 // No more steps are allowed return } }
  51. 75.

    class <anonymous_for_state_machine> extends CoroutineImpl<...> implements Continuation<Object> { // The current

    state of the state machine int label = 0 // local variables of the coroutine A a = null Y y = null void resume(Object data) { if (label == 0) goto L0 if (label == 1) goto L1 if (label == 2) goto L2 else throw IllegalStateException() L0: // data is expected to be `null` at this invocation a = a() label = 1 data = foo(a).await(this) // 'this' is passed as a continuation if (data == COROUTINE_SUSPENDED) return // return if await had suspended execution L1: // external code has resumed this coroutine passing the result of .await() as data y = (Y) data b() label = 2 data = bar(a, y).await(this) // 'this' is passed as a continuation if (data == COROUTINE_SUSPENDED) return // return if await had suspended execution L2: // external code has resumed this coroutine passing the result of .await() as data Z z = (Z) data c(z) label = -1 // No more steps are allowed return } }