I'm trying to use Scala (2.9.0) continuations to build a seemingly blocking API, but that actually is asynchronous. Suppose that you would like to write something like:
if(ask("Continue?")) //Prompts Yes/No
name = input("Enter your name")
Where ask
returns a boolean if the user pressed yes, and input
asks for a value. Picture this being called from a web server, where ask
and input
do not block any threads, they just store a continuation in a Map (or the session, doesn't matter much) before displaying the page with the prompt (releasing most resources). And when a response get's back, it looks-up the continuation in the Map and resumes the code.
The problem so far is that I cannot seem to be able to find a suitable way to define ask
and input
to use continuations without passing the calling context's return type as a parameter.
The closest I got is doing something like:
#!/bin/sh
exec scala -P:continuations:enable -deprecation "$0" "$@"
!#
import util.continuations._
//Api code
def display[T](prompt: String) = shift {
cont: (Unit => T) => {
println(prompt)
cont()
}
}
//Client code
def foo() : Int = reset {
display[Int]("foo!") // <-- how do I get rid of the type annotation?
5
}
def bar() : Unit = reset {
display[Unit]("bar!")
}
println(foo())
bar()
I really would like to get rid of the type annotation on calls to display
. Does anyone know of a way of achieving this? I don't care if the API definition gets uglier, as long as the client code gets simpler.
Thanks!
I finally figured it out:
#!/bin/sh
exec scala -P:continuations:enable -deprecation "$0" "$@"
!#
import util.continuations._
class Display(val resume: (Unit => Any)) extends Throwable
//Api code
def display(prompt: String) = shift {
cont: (Unit => Any) => {
println(prompt)
throw new Display(cont)
}
}
//Client code
def foo() : Int = reset {
display("foo!")
5
}
def bar() : Unit = reset {
display("bar!")
}
//Framework
try {
foo()
} catch {
case d: Display => println(d.resume())
}
try {
bar()
} catch {
case d: Display => d.resume()
}
The trick is accepting methods that return Any
(Homeresque: D'oh!) and returning Nothing
.
If you want to implement something that returns a value, such as ask
, you can do:
class Ask(val resume: (Boolean => Any)) extends Throwable
//Api code
def ask(prompt: String) = shift {
cont: (Boolean => Any) => {
println(prompt)
throw new Ask(cont)
}
}
In the above code, ask returns a Boolean
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With