Corou%nes	
  in	
  Kotlin	
  
Andrey.Breslav@JetBrains.com	
  
This	
  talk	
  could	
  have	
  been	
  named…	
  
•  async/await/yield	
  
•  fibers	
  
•  [stackless]	
  con%nua%ons	
  
Suspendable	
  
Computa%ons	
  
Outline	
  
•  Mo%va%on/Examples	
  
•  Solu%ons	
  in	
  other	
  languages	
  
•  Kotlin’s	
  Solu%on	
  
–  Client	
  code	
  
–  Library	
  code	
  
•  Compiling	
  Corou%nes	
  
•  Excep%on	
  Handling	
  
•  Appendix.	
  Serializable	
  Corou%nes?	
  
“Legal”	
  
•  All	
  I’m	
  saying	
  is	
  no	
  more	
  final	
  than	
  Valhalla	
  J	
  
 
val	
  image	
  =	
  loadImage(url)	
  
myUI.setImage(image)	
  
	
  
Mo%va%on	
  
Time-­‐consuming	
  
opera%on	
  
UI	
  Thread	
  
Latency!	
  
•  Blocking	
  bad.	
  Very	
  bad.	
  
asyncUI	
  {	
  
val	
  image	
  =	
  await(loadImage(url))	
  
myUI.setImage(image)	
  
}	
  
Suspendable	
  Computa%on	
  
Suspending	
  
call	
  
Con%nua%on	
  
Time-­‐consuming	
  
opera%on	
  
await(…)	
   loadImage(url)	
  
UI	
  Thread	
  
Worker	
  Thread	
  
setImage(…)	
  
“Callback	
  Hell”	
  
Combining	
  Futures	
  
•  CompletableFuture	
  
  .supplyAsync	
  {	
  loadImage(url)	
  }	
  
  .thenAccept(myUI::setImage)	
  
•  so	
  veeery	
  func%onal	
  J	
  
asyncUI	
  {	
  
val	
  image	
  =	
  loadImageAsync(url)	
  
myUI.setImage(image)	
  
}	
  
Flexibility	
  
Asynchronous	
  
opera%on	
  
Con%nua%on	
  
interface	
  Continuation<P>	
  {	
  
	
  	
  	
  	
  fun	
  resume(data:	
  P)	
  
	
  	
  	
  	
  fun	
  resumeWithException(e:	
  Throwable)	
  
}	
  
<Image>	
  
Library	
  Func%on	
  
(corou%ne	
  builder)	
  
asyncUI	
  {	
  
val	
  image	
  =	
  await(loadImage(url))	
  
myUI.setImage(image)	
  
}	
  
Run%me	
  Support	
  
Con%nua%on	
  
interface	
  Continuation<P>	
  {	
  
	
  	
  	
  	
  fun	
  resume(data:	
  P)	
  
	
  	
  	
  	
  fun	
  resumeWithException(e:	
  Throwable)	
  
}	
  
<Image>	
  
Summary:	
  Goals	
  
•  Asynchronous	
  programing	
  (and	
  more)	
  
–  without	
  explicit	
  callbacks	
  
–  without	
  explicit	
  Future	
  combinators	
  
•  Maximum	
  flexibility	
  for	
  library	
  designers	
  
–  with	
  minimal	
  run%me	
  support	
  
–  and	
  no	
  macros	
  J	
  
Flavors	
  of	
  Corou%nes	
  
Stackless	
   Stackful	
  
Language	
  restric;ons	
   Use	
  in	
  special	
  contexts	
  L	
   Use	
  anywhere	
  J	
  
Implemented	
  in	
   C#,	
  Scala,	
  Kotlin,	
  …	
   Quasar,	
  Javaflow,	
  …	
  
Code	
  transforma;on	
   Local	
  (compiler	
  magic)	
  J	
   All	
  over	
  the	
  place	
  L	
  
Run;me	
  support	
   Lidle	
  J	
   Substan%al	
  L	
  
The	
  C#	
  Way	
  
async	
  Task<String>	
  work()	
  {	
  
Thread.sleep(200);	
  
return	
  “done”;	
  
}	
  
	
  
async	
  Task	
  moreWork()	
  {	
  
Console.WriteLine(“Work	
  started”);	
  
var	
  str	
  =	
  await	
  work();	
  
Console.WriteLine($“Work	
  completed:	
  {str}”);	
  
}	
  
Example:	
  async/await	
  (I)	
  
fun work(): CompletableFuture<String> = async {!
Thread.sleep(200)!
"done"!
}!
!
fun moreWork() = async {!
println("Work started")!
val str = await(work())!
println("Work completed: $str")!
}	
  
type	
  is	
  op%onal	
  
Example:	
  async/await	
  (I)	
  
fun work() = async {!
Thread.sleep(200)!
"done"!
}!
!
fun moreWork() = async {!
println("Work started")!
val str = await(work())!
println("Work completed: $str")!
}	
  
await()	
  
fun moreWork() = async {!
println("Work started")!
val str = await(work())!
println("Work completed: $str")!
}!
!
suspend fun <V> await(f: CompletableFuture<V>, c: Continuation<V>) {!
f.whenComplete { value, throwable ->!
if (throwable == null)!
c.resume(value)!
else!
c.resumeWithException(throwable)!
}!
}!
!
async()	
  
fun moreWork() = async {!
println("Work started")!
val str = await(work())!
println("Work completed: $str")!
}!
!
fun <T> async(!
coroutine c: FutureController<T>.() -> Continuation<Unit>!
): CompletableFuture<T> {!
val controller = FutureController<T>()!
c(controller).resume(Unit)!
return controller.future!
}!
implicit	
  receiver	
   λ	
  has	
  no	
  params	
  
Controller	
  
@AllowSuspendExtensions!
class FutureController<T> {!
internal val future = CompletableFuture<T>()!
!
suspend fun <V> await(f: CompletableFuture<V>, c: Continuation<V>) {!
f.whenComplete { value, throwable ->!
if (throwable == null)!
c.resume(value)!
else!
c.resumeWithException(throwable)!
}!
}!
!
operator fun handleResult(value: T, c: Continuation<Nothing>) {!
future.complete(value)!
}!
!
operator fun handleException(t: Throwable, c: Continuation<Nothing>) {!
future.completeExceptionally(t)!
}!
}!
fun work() = async {!
Thread.sleep(200)!
"done"!
}!
Extensibility	
  
suspend fun <V> FutureController<*>.await(!
lf: ListenableFuture<V>, c: Continuation<V>!
) {!
Futures.addCallback(lf, object : FutureCallback<V> { !
override fun onSuccess(value: V) {!
c.resume(value)!
}!
override fun onFailure(e: Throwable) {!
c.resumeWithException(throwable)!
}!
})!
}!
!
// Example!
async {!
val res1 = await(getCompletableFuture()) !
val res2 = await(getListeableFuture())!
}!
Summary:	
  Corou%ne	
  Libraries	
  
•  fun	
  async(coroutine	
  c:	
  …)	
  
–  func%on	
  with	
  a	
  coroutine parameter	
  
	
  
•  suspend	
  fun	
  await(…,	
  c:	
  Continuation<…>)	
  
–  func%on	
  marked	
  suspend !
–  con%nua%on	
  is	
  implicitly	
  passed	
  in	
  at	
  the	
  call	
  site	
  
	
  
•  class	
  Controller	
  
–  declares	
  suspend func%ons	
  
•  may	
  allow	
  suspend extensions	
  
–  declares	
  return/excep%on	
  handlers	
  
How	
  Suspension	
  Works	
  
fun moreWork() = async {!
println("Work started")!
val str = await(work())!
println("Work completed: $str")!
}!
!
!
!
!
!
!
!
!
!
.!
controller.await(!
work(), !
current_continuation!
)!
return!
Yield	
  (The	
  C#	
  Way)	
  
IEnumerable<int>	
  Fibonacci()	
  {	
  
	
  	
  	
  	
  var	
  cur	
  =	
  1;	
  
	
  	
  	
  	
  var	
  next	
  =	
  1;	
  
	
  
	
  	
  	
  	
  yield	
  return	
  1;	
  
	
  
	
  	
  	
  	
  while	
  (true)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  yield	
  return	
  next;	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  var	
  tmp	
  =	
  cur	
  +	
  next;	
  
	
  	
  	
  	
  	
  	
  	
  	
  cur	
  =	
  next;	
  
	
  	
  	
  	
  	
  	
  	
  	
  next	
  =	
  tmp;	
  
	
  	
  	
  	
  }	
  
}	
  
Infinite	
  (lazy)	
  sequence	
  of	
  	
  
Fibonacci	
  numbers	
  
Example:	
  Lazy	
  Fibonacci	
  
val fibonacci: Sequence<Int> = generate {!
var cur = 1!
var next = 1!
!
yield(1)!
!
while (true) {!
yield(next)!
!
val tmp = cur + next!
cur = next!
next = tmp!
}!
}!
!
assertEquals("1, 1, 2, 3, 5", fibonacci.take(5).joinToString())	
  
fun <T> generate(!
coroutine c: GeneratorController<T>.() -> Continuation<Unit>!
): Sequence<T> =!
object : Sequence<T> {!
override fun iterator(): Iterator<T> {!
val iterator = GeneratorController<T>()!
iterator.setNextStep(c(iterator))!
return iterator!
}!
}!
!
class GeneratorController<T> : AbstractIterator<T>() {!
...!
suspend fun yield(value: T, c: Continuation<Unit>) {!
setNext(value)!
setNextStep(c)!
}!
...!
}	
  
Compiling	
  to	
  State	
  Machines	
  
generate {!
var cur = 1!
var next = 1!
!
yield(1)!
!
while (true) {!
yield(next)!
!
val tmp = cur + next!
cur = next!
next = tmp!
}!
}	
  
L0	
  
L1	
  
L2	
  
var cur = 1!
var next = 1	
  
true	
  
val tmp = cur + next!
cur = next!
next = tmp!
val fibonacci = generate {!
var cur = 1!
var next = 1!
!
yield(1)!
!
while (true) {!
yield(next)!
!
val tmp = cur + next!
cur = next!
next = tmp!
}!
}	
  
Compiling	
  Corou%nes	
  (I)	
  
class fibonacci$1 implements Function1, !
Continuation {!
	
  
	
  	
  	
  	
  volatile	
  GeneratorController	
  controller	
  
	
  	
  	
  	
  volatile	
  int	
  label	
  =	
  -­‐2	
  
	
  
	
  	
  	
  	
  volatile	
  int	
  cur	
  
	
  	
  	
  	
  volatile	
  int	
  next	
  
	
  
	
  
	
  	
  	
  	
  public	
  Continuation<Unit>	
  invoke(	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  GeneratorController	
  controller)	
  
	
  
	
  	
  	
  	
  public	
  void	
  resume(Object	
  param)	
  
	
  	
  	
  	
  public	
  void	
  resumeWithException(Throwable	
  e)	
  
	
  	
  	
  	
  private	
  void	
  doResume(Object	
  param,	
  Throwable	
  e)	
   	
  	
  
}	
  
for	
  shared	
  local	
  variables	
  
Compiling	
  Corou%nes	
  (II)	
  
•  Fields:	
  
–  GeneratorController	
  controller	
  
–  int	
  label	
  
	
  
	
  
•  void	
  doResume(Object	
  param,	
  Throwable	
  e)	
  
–  tableswitch	
  (label)	
  
  case	
  0:	
  L0	
  
  case	
  1:	
  L1	
  
  case	
  2:	
  L2	
  
–  L0:	
  
  ...	
  
  label	
  =	
  1	
  
  controller.yield(1,	
  /*	
  continuation	
  =	
  */	
  this)	
  
  return	
  
–  L1:	
  
  ...	
  
  label	
  =	
  2	
  
  controller.yield(next,	
  /*	
  continuation	
  =	
  */	
  this)	
  
  return	
  
–  L2:	
  
  ...	
  
L0	
  
L1	
  
L2	
  
var cur = 1!
var next = 1	
  
true	
  
val tmp = cur + next!
cur = next!
next = tmp!
Compiling	
  Corou%nes	
  (III)	
  
–  L0:	
  
  var	
  cur	
  =	
  1	
  
  var	
  next	
  =	
  1	
  
  this.cur	
  =	
  cur	
  
  this.next	
  =	
  next	
  
  this.label	
  =	
  1	
  
  this.controller.yield(1,	
  this)	
  
  return	
  
L0	
  
L1	
  
L2	
  
var cur = 1!
var next = 1	
  
Compiling	
  Corou%nes	
  (IV)	
  
•  void	
  doResume(Object	
  param,	
  Throwable	
  e)	
  
–  L1:	
  
  cur	
  =	
  this.cur	
  
  next	
  =	
  this.next	
  
  if	
  (e	
  !=	
  null)	
  throw	
  e	
  
  //	
  while	
  (true)	
  {	
  
  this.cur	
  =	
  cur	
  
  this.next	
  =	
  next	
  
  this.label	
  =	
  2	
  
  this.controller.yield(next,	
  this)	
  
  return	
  
L0	
  
L1	
  
L2	
  
true	
  
Summary:	
  Compiling	
  Corou%nes	
  
•  Note:	
  generate()/yield()	
  can	
  be	
  expressed	
  	
  
–  flexibility:	
  þ
•  Corou%ne	
  body	
  is	
  compiled	
  to	
  a	
  state	
  machine	
  
•  Only	
  one	
  instance	
  is	
  allocated	
  at	
  run%me	
  
asyncUI	
  {	
  	
  
val	
  image	
  =	
  await(loadImage(url))	
  
myUI.setImage(image)	
  
}	
  
IOExcep%on	
  
CannotAwaitExcep%on	
  
WindowDisposedExcep%on	
  
Excep%on	
  Handling	
  
Throwing	
  and	
  Catching	
  
•  Who	
  can	
  throw	
  
–  Synchronous	
  code	
  (inside	
  a	
  corou%ne)	
  
–  Asynchronous	
  opera%ons	
  (called	
  from	
  corou%ne)	
  
–  Library	
  code	
  (that	
  manages	
  the	
  corouitne)	
  
•  Who	
  can	
  catch	
  
–  The	
  corou%ne	
  itself	
  (user	
  code)	
  
–  Library	
  code	
  
Controller.handleExcep%on(e)	
  
void	
  doResume(Object	
  param,	
  Throwable	
  e)	
  
	
  
tableswitch	
  (label)	
  
case	
  0:	
  L0	
  
case	
  1:	
  L1	
  
case	
  2:	
  L2	
  
try	
  {	
  
  L0:	
  
  ...	
  
  label	
  =	
  1	
  
  controller.await(...,	
  /*	
  continuation	
  =	
  */	
  this)	
  
  return	
  
  L1:	
  
  ...	
  
  label	
  =	
  2	
  
  controller.await(...,	
  /*	
  continuation	
  =	
  */	
  this)	
  
  return	
  
  L2:	
  
  ...	
  
  }	
  catch	
  (Throwable	
  e)	
  {	
  
  controller.handleException(e)	
  
  }	
  
Rou%ng	
  Asynchronous	
  Excep%ons	
  
•  void	
  doResume(Object	
  param,	
  Throwable	
  e)	
  
	
  	
  	
  ...	
  
–  L1:	
  
  //	
  fields	
  -­‐>	
  locals	
  
  if	
  (e	
  !=	
  null)	
  throw	
  e	
  
  ...	
  
  //	
  locals	
  -­‐>	
  fields	
  
  this.label	
  =	
  2	
  
  this.controller.yield(next,	
  this)	
  
  return	
  
suspend fun await(f, c) {!
f.whenComplete { value, e ->!
if (throwable == null)!
c.resume(value)!
else!
c.resumeWithException(e)	
  
Example:	
  Excep%on	
  Handling	
  
asyncUI	
  {	
  
	
  	
  	
  	
  val	
  image	
  =	
  try	
  {	
  
	
  	
  	
  	
  	
  	
  	
  await(	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  loadImage(url)	
  
	
  	
  	
  	
  	
  	
  	
  )	
  
	
  	
  	
  	
  }	
  catch(e:	
  Exception)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  log(e)	
  
	
  	
  	
  	
  	
  	
  	
  	
  throw	
  e	
  
	
  	
  	
  	
  }	
  
	
  
	
  	
  	
  	
  myUI.setImage(image)	
  
}	
  
Operation	
  order:	
  
•  loadImage(url)	
  
•  -­‐>	
  tmp_future	
  
•  -­‐>	
  actual_work()	
  
•  await(tmp_future)	
  
•  <suspend>	
  
•  actual_work()	
  completes	
  
•  <resume>	
  
•  myUI.setImage(image)	
  
actual_work(url)	
  
worker	
  	
  
thread	
  
Summary:	
  Excep%on	
  Handling	
  
•  Uniform	
  treatment	
  of	
  all	
  excep%ons	
  
–  both	
  sync	
  and	
  async	
  
•  Default	
  handler:	
  controller.handleException(e)	
  
•  Not	
  covered	
  in	
  this	
  talk	
  
–  Suspending	
  in	
  finally	
  blocks	
  
–  Calling	
  finally	
  blocks	
  through	
  Continuation<T>	
  
Appendix.	
  Serializable	
  Corou%nes?	
  
serializableAsync(getDB())	
  {	
  
	
  	
  	
  	
  val	
  newUser	
  =	
  showRegistrationForm()	
  
	
  	
  	
  	
  sendConfirmationEmail(newUser)	
  
	
  	
  	
  	
  if	
  (awaitEmailAddressConfirmation(newUser))	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  registration	
  confirmed	
  in	
  time	
  
	
  	
  	
  	
  	
  	
  	
  	
  confirmRegistration(getDB(),	
  newUser)	
  
	
  	
  	
  	
  	
  	
  	
  	
  showWelcomeScreen(newUser)	
  
	
  	
  	
  	
  }	
  else	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  registration	
  not	
  confirmed	
  
	
  	
  	
  	
  	
  	
  	
  	
  cancelRegistration(getDB(),	
  newUser)	
  
	
  	
  	
  	
  }	
  
}	
  
Suspending	
  	
  
Calls	
  
Data	
  to	
  be	
  serialized:	
  
•  label	
  (state	
  of	
  the	
  SM)	
  
•  newUser	
  

JVMLS 2016. Coroutines in Kotlin

  • 1.
    Corou%nes  in  Kotlin   Andrey.Breslav@JetBrains.com  
  • 2.
    This  talk  could  have  been  named…   •  async/await/yield   •  fibers   •  [stackless]  con%nua%ons   Suspendable   Computa%ons  
  • 3.
    Outline   •  Mo%va%on/Examples   •  Solu%ons  in  other  languages   •  Kotlin’s  Solu%on   –  Client  code   –  Library  code   •  Compiling  Corou%nes   •  Excep%on  Handling   •  Appendix.  Serializable  Corou%nes?  
  • 4.
    “Legal”   •  All  I’m  saying  is  no  more  final  than  Valhalla  J  
  • 5.
      val  image  =  loadImage(url)   myUI.setImage(image)     Mo%va%on   Time-­‐consuming   opera%on   UI  Thread  
  • 6.
    Latency!   •  Blocking  bad.  Very  bad.  
  • 7.
    asyncUI  {   val  image  =  await(loadImage(url))   myUI.setImage(image)   }   Suspendable  Computa%on   Suspending   call   Con%nua%on   Time-­‐consuming   opera%on   await(…)   loadImage(url)   UI  Thread   Worker  Thread   setImage(…)  
  • 8.
  • 9.
    Combining  Futures   • CompletableFuture     .supplyAsync  {  loadImage(url)  }     .thenAccept(myUI::setImage)   •  so  veeery  func%onal  J  
  • 10.
    asyncUI  {   val  image  =  loadImageAsync(url)   myUI.setImage(image)   }   Flexibility   Asynchronous   opera%on   Con%nua%on   interface  Continuation<P>  {          fun  resume(data:  P)          fun  resumeWithException(e:  Throwable)   }   <Image>   Library  Func%on   (corou%ne  builder)  
  • 11.
    asyncUI  {   val  image  =  await(loadImage(url))   myUI.setImage(image)   }   Run%me  Support   Con%nua%on   interface  Continuation<P>  {          fun  resume(data:  P)          fun  resumeWithException(e:  Throwable)   }   <Image>  
  • 12.
    Summary:  Goals   • Asynchronous  programing  (and  more)   –  without  explicit  callbacks   –  without  explicit  Future  combinators   •  Maximum  flexibility  for  library  designers   –  with  minimal  run%me  support   –  and  no  macros  J  
  • 13.
    Flavors  of  Corou%nes   Stackless   Stackful   Language  restric;ons   Use  in  special  contexts  L   Use  anywhere  J   Implemented  in   C#,  Scala,  Kotlin,  …   Quasar,  Javaflow,  …   Code  transforma;on   Local  (compiler  magic)  J   All  over  the  place  L   Run;me  support   Lidle  J   Substan%al  L  
  • 14.
    The  C#  Way   async  Task<String>  work()  {   Thread.sleep(200);   return  “done”;   }     async  Task  moreWork()  {   Console.WriteLine(“Work  started”);   var  str  =  await  work();   Console.WriteLine($“Work  completed:  {str}”);   }  
  • 15.
    Example:  async/await  (I)   fun work(): CompletableFuture<String> = async {! Thread.sleep(200)! "done"! }! ! fun moreWork() = async {! println("Work started")! val str = await(work())! println("Work completed: $str")! }   type  is  op%onal  
  • 16.
    Example:  async/await  (I)   fun work() = async {! Thread.sleep(200)! "done"! }! ! fun moreWork() = async {! println("Work started")! val str = await(work())! println("Work completed: $str")! }  
  • 17.
    await()   fun moreWork()= async {! println("Work started")! val str = await(work())! println("Work completed: $str")! }! ! suspend fun <V> await(f: CompletableFuture<V>, c: Continuation<V>) {! f.whenComplete { value, throwable ->! if (throwable == null)! c.resume(value)! else! c.resumeWithException(throwable)! }! }! !
  • 18.
    async()   fun moreWork()= async {! println("Work started")! val str = await(work())! println("Work completed: $str")! }! ! fun <T> async(! coroutine c: FutureController<T>.() -> Continuation<Unit>! ): CompletableFuture<T> {! val controller = FutureController<T>()! c(controller).resume(Unit)! return controller.future! }! implicit  receiver   λ  has  no  params  
  • 19.
    Controller   @AllowSuspendExtensions! class FutureController<T>{! internal val future = CompletableFuture<T>()! ! suspend fun <V> await(f: CompletableFuture<V>, c: Continuation<V>) {! f.whenComplete { value, throwable ->! if (throwable == null)! c.resume(value)! else! c.resumeWithException(throwable)! }! }! ! operator fun handleResult(value: T, c: Continuation<Nothing>) {! future.complete(value)! }! ! operator fun handleException(t: Throwable, c: Continuation<Nothing>) {! future.completeExceptionally(t)! }! }! fun work() = async {! Thread.sleep(200)! "done"! }!
  • 20.
    Extensibility   suspend fun<V> FutureController<*>.await(! lf: ListenableFuture<V>, c: Continuation<V>! ) {! Futures.addCallback(lf, object : FutureCallback<V> { ! override fun onSuccess(value: V) {! c.resume(value)! }! override fun onFailure(e: Throwable) {! c.resumeWithException(throwable)! }! })! }! ! // Example! async {! val res1 = await(getCompletableFuture()) ! val res2 = await(getListeableFuture())! }!
  • 21.
    Summary:  Corou%ne  Libraries   •  fun  async(coroutine  c:  …)   –  func%on  with  a  coroutine parameter     •  suspend  fun  await(…,  c:  Continuation<…>)   –  func%on  marked  suspend ! –  con%nua%on  is  implicitly  passed  in  at  the  call  site     •  class  Controller   –  declares  suspend func%ons   •  may  allow  suspend extensions   –  declares  return/excep%on  handlers  
  • 22.
    How  Suspension  Works   fun moreWork() = async {! println("Work started")! val str = await(work())! println("Work completed: $str")! }! ! ! ! ! ! ! ! ! ! .! controller.await(! work(), ! current_continuation! )! return!
  • 23.
    Yield  (The  C#  Way)   IEnumerable<int>  Fibonacci()  {          var  cur  =  1;          var  next  =  1;            yield  return  1;            while  (true)  {                  yield  return  next;                    var  tmp  =  cur  +  next;                  cur  =  next;                  next  =  tmp;          }   }   Infinite  (lazy)  sequence  of     Fibonacci  numbers  
  • 24.
    Example:  Lazy  Fibonacci   val fibonacci: Sequence<Int> = generate {! var cur = 1! var next = 1! ! yield(1)! ! while (true) {! yield(next)! ! val tmp = cur + next! cur = next! next = tmp! }! }! ! assertEquals("1, 1, 2, 3, 5", fibonacci.take(5).joinToString())  
  • 25.
    fun <T> generate(! coroutinec: GeneratorController<T>.() -> Continuation<Unit>! ): Sequence<T> =! object : Sequence<T> {! override fun iterator(): Iterator<T> {! val iterator = GeneratorController<T>()! iterator.setNextStep(c(iterator))! return iterator! }! }! ! class GeneratorController<T> : AbstractIterator<T>() {! ...! suspend fun yield(value: T, c: Continuation<Unit>) {! setNext(value)! setNextStep(c)! }! ...! }  
  • 26.
    Compiling  to  State  Machines   generate {! var cur = 1! var next = 1! ! yield(1)! ! while (true) {! yield(next)! ! val tmp = cur + next! cur = next! next = tmp! }! }   L0   L1   L2   var cur = 1! var next = 1   true   val tmp = cur + next! cur = next! next = tmp!
  • 27.
    val fibonacci =generate {! var cur = 1! var next = 1! ! yield(1)! ! while (true) {! yield(next)! ! val tmp = cur + next! cur = next! next = tmp! }! }   Compiling  Corou%nes  (I)   class fibonacci$1 implements Function1, ! Continuation {!          volatile  GeneratorController  controller          volatile  int  label  =  -­‐2            volatile  int  cur          volatile  int  next              public  Continuation<Unit>  invoke(                                                GeneratorController  controller)            public  void  resume(Object  param)          public  void  resumeWithException(Throwable  e)          private  void  doResume(Object  param,  Throwable  e)       }   for  shared  local  variables  
  • 28.
    Compiling  Corou%nes  (II)   •  Fields:   –  GeneratorController  controller   –  int  label       •  void  doResume(Object  param,  Throwable  e)   –  tableswitch  (label)     case  0:  L0     case  1:  L1     case  2:  L2   –  L0:     ...     label  =  1     controller.yield(1,  /*  continuation  =  */  this)     return   –  L1:     ...     label  =  2     controller.yield(next,  /*  continuation  =  */  this)     return   –  L2:     ...   L0   L1   L2   var cur = 1! var next = 1   true   val tmp = cur + next! cur = next! next = tmp!
  • 29.
    Compiling  Corou%nes  (III)   –  L0:     var  cur  =  1     var  next  =  1     this.cur  =  cur     this.next  =  next     this.label  =  1     this.controller.yield(1,  this)     return   L0   L1   L2   var cur = 1! var next = 1  
  • 30.
    Compiling  Corou%nes  (IV)   •  void  doResume(Object  param,  Throwable  e)   –  L1:     cur  =  this.cur     next  =  this.next     if  (e  !=  null)  throw  e     //  while  (true)  {     this.cur  =  cur     this.next  =  next     this.label  =  2     this.controller.yield(next,  this)     return   L0   L1   L2   true  
  • 31.
    Summary:  Compiling  Corou%nes   •  Note:  generate()/yield()  can  be  expressed     –  flexibility:  þ •  Corou%ne  body  is  compiled  to  a  state  machine   •  Only  one  instance  is  allocated  at  run%me  
  • 32.
    asyncUI  {     val  image  =  await(loadImage(url))   myUI.setImage(image)   }   IOExcep%on   CannotAwaitExcep%on   WindowDisposedExcep%on   Excep%on  Handling  
  • 33.
    Throwing  and  Catching   •  Who  can  throw   –  Synchronous  code  (inside  a  corou%ne)   –  Asynchronous  opera%ons  (called  from  corou%ne)   –  Library  code  (that  manages  the  corouitne)   •  Who  can  catch   –  The  corou%ne  itself  (user  code)   –  Library  code  
  • 34.
    Controller.handleExcep%on(e)   void  doResume(Object  param,  Throwable  e)     tableswitch  (label)   case  0:  L0   case  1:  L1   case  2:  L2   try  {     L0:     ...     label  =  1     controller.await(...,  /*  continuation  =  */  this)     return     L1:     ...     label  =  2     controller.await(...,  /*  continuation  =  */  this)     return     L2:     ...     }  catch  (Throwable  e)  {     controller.handleException(e)     }  
  • 35.
    Rou%ng  Asynchronous  Excep%ons   •  void  doResume(Object  param,  Throwable  e)        ...   –  L1:     //  fields  -­‐>  locals     if  (e  !=  null)  throw  e     ...     //  locals  -­‐>  fields     this.label  =  2     this.controller.yield(next,  this)     return   suspend fun await(f, c) {! f.whenComplete { value, e ->! if (throwable == null)! c.resume(value)! else! c.resumeWithException(e)  
  • 36.
    Example:  Excep%on  Handling   asyncUI  {          val  image  =  try  {                await(                        loadImage(url)                )          }  catch(e:  Exception)  {                  log(e)                  throw  e          }            myUI.setImage(image)   }   Operation  order:   •  loadImage(url)   •  -­‐>  tmp_future   •  -­‐>  actual_work()   •  await(tmp_future)   •  <suspend>   •  actual_work()  completes   •  <resume>   •  myUI.setImage(image)   actual_work(url)   worker     thread  
  • 37.
    Summary:  Excep%on  Handling   •  Uniform  treatment  of  all  excep%ons   –  both  sync  and  async   •  Default  handler:  controller.handleException(e)   •  Not  covered  in  this  talk   –  Suspending  in  finally  blocks   –  Calling  finally  blocks  through  Continuation<T>  
  • 38.
    Appendix.  Serializable  Corou%nes?   serializableAsync(getDB())  {          val  newUser  =  showRegistrationForm()          sendConfirmationEmail(newUser)          if  (awaitEmailAddressConfirmation(newUser))  {                  //  registration  confirmed  in  time                  confirmRegistration(getDB(),  newUser)                  showWelcomeScreen(newUser)          }  else  {                  //  registration  not  confirmed                  cancelRegistration(getDB(),  newUser)          }   }   Suspending     Calls   Data  to  be  serialized:   •  label  (state  of  the  SM)   •  newUser  

Editor's Notes

  • #2 A rarity: Language design talk As Brian and Dan mention every time in the last few years, we started as “here’s my language, look how cool it is”, and now JVMLS means more a summit of people who speak the JVM language 
  • #7 A car blocking others Blocking one’s driveway
  • #10 It helps, but async/await is so much more straightforward