- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
C# async implemented in scala (based on delimited continuations)
Thu, 2012-02-16, 01:28
Hi all
In order to get a better understanding about delimited continuations I
tried to implement something akin to C# async [1]. Since I think this
has the potential to be cool, I share it with you. I would appreciate
any hints and comments.
As a substitute for C#s Tasks I went with akka 2.0 Futures [2] since
those will eventually be integrated into the main library [3] afaik.
I have the following:
== Example ==
context(GUI) { implicit ec =>
async {
m("1")
val contentCom = await { dlWebSite("http://www.google.com") }
m("2 " + contentCom)
val contentCh = await { dlWebSite("http://www.google.ch") }
m("3 " + contentCh)
val contentDe = await { dlWebSite("http://www.google.de") }
m("4 " + contentDe)
}
}
// Returns a Future which will eventually hold the downloaded html.
// The download itself is scheduled on a thread pool.
def dlWebSite(url: String): Future[String] = Future {
m("downloading: " + url)
Source.fromURL(new URL(url))
(Codec.ISO8859).getLines.mkString.take(20)
}(ThreadPool)
// Prints msg prefixed with the name of the current thread
def m(msg: String) = println(Thread.currentThread().getName() + " '" +
msg + "'")
== Output ==
UI '1'
pool-1-thread-1 'downloading: http://www.google.com'
UI '2 Unit@suspendable): Unit = reset[Unit,Unit]
{ block }
// The await method takes a block which returns a Future[A] and
// pretends to return an A to the caller. Without continuations, this
would be
// only possible by waiting (blocking) on the future until the result
is ready.
def await[A](block: => Future[A])(implicit ec: ExecutionContext =
ThreadPool): A@suspendable = shift { cont: (A => Unit) =>
block onSuccess { case r => ec.execute{ cont(r) } }
}
// The context method is used to put an ExecutionContext into scope
// which runs the given block. It primarily exists to give nice
// looking examples.
def context[T](ec: ExecutionContext)(block: ExecutionContext => T)
{ ec.execute{ block(ec) } }
// Dummy placeholder to simulate the Swing event dispatching thread
val GUI =
ExecutionContexts.fromExecutor(Executors.newSingleThreadExecutor(
new ThreadFactory{ def newThread(r: Runnable): Thread = new
Thread(r,"UI")}))
// Thread pool for the heavy background work
val ThreadPool = ExecutionContexts.fromExecutorService(
Executors.newFixedThreadPool(10))
// Runnables without the noise
implicit def toRunnable[T](f: => T ): Runnable = new Runnable { def
run() = f }
== The Problem ==
I would like the async block to return a Future of its syntactic
return value:
val a: Future[Int] = async[Int] {
m("1")
val com = await[String,Int,NotLast] {
dlWebSite("http://www.google.com")
}
m("2 " + com)
val ch = await[String,Int,NotLast] {
dlWebSite("http://www.google.ch")
}
m("3 " + ch)
val de = await[String,Int,Last] {
dlWebSite("http://www.google.de")
}
m("4 " + de)
de.length() // this should be returned as a Future[Int]
}
a onSuccess { case r => m("res" + r) }
== Output ==
UI '1'
pool-1-thread-1 'downloading: http://www.google.com'
UI '2 B@cpsParam[B,Future[B]]): Future[B] =
reset[B,Future[B]] { block }
// The D[_] type parameter is required in @cpsParam.
// Depending on the given type the matching implicit is searched.
def await[A,B,D[_]] (block: => Future[A])
(implicit ec: ExecutionContext = ThreadPool,
f: (=> Future[A]) => ExecutionContext => A@cpsParam[D[B],Future[B]]
):A@cpsParam[D[B],Future[B]] = f(block)(ec)
type Last[X] = X
// The last await needs a continuation form A => Last[B] which is from
A => B
implicit def last[A,B]: (=> Future[A]) => ExecutionContext =>
A@cpsParam[Last[B],Future[B]] = {
block => ec => shift[A,Last[B],Future[B]] { cont: (A => Last[B]) =>
val p = Promise[B]()(ec)
block onSuccess { case a => ec.execute{ p.success(cont(a)) } }
p
}
}
type NotLast[X] = Future[X]
// All other awaits need a continuation from A => NotLast[B]
// which is from A => Future[B]
implicit def notLast[A,B]: (=> Future[A]) => ExecutionContext =>
A@cpsParam[NotLast[B],Future[B]] = {
block => ec => shift[A,NotLast[B],Future[B]] { cont: (A =>
NotLast[B]) =>
val p = Promise[B]()(ec)
block onSuccess { case a =>
ec.execute{ p.completeWith(cont(a)) } }
p
}
}
This was the best solution I was able to come up with. Of course I
could offer two different await methods which would be a simple
solution if they had different names. But that is not an option. BTW I
am fully aware that the presented code has at most toy quality (
handles only onSuccess, etc.). Anyway, thanks for reading that far. If
you want to learn about scala's continuations I recommend reading this
blog post [4] by Jim McBeath.
Thanks Daniel
[1] http://msdn.microsoft.com/en-us/vstudio/gg316360
[2] http://akka.io/docs/akka/2.0-RC1/scala/futures.html
[3] http://docs.scala-lang.org/sips/pending/futures-promises.html
[4] http://jim-mcbeath.blogspot.com/2010/08/delimited-continuations.html
Thu, 2012-02-16, 12:51
#2
Re: C# async implemented in scala (based on delimited continuat
I think we already got this covered with the dataflow API in Akka:
http://akka.io/docs/akka/2.0-RC1/scala/dataflow.html
Cheers,
√
On Thu, Feb 16, 2012 at 12:40 PM, Tiark Rompf wrote:
> Sweet! Would this version of async
>
> def async[A](body: => A @suspendable) = {
> val p = promise[A]
> reset { p success body }
> p
> }
>
> work for the extended case you mention?
>
> val a: Future[Int] = async[Int] {
> val com = await { dlWebSite("http://www.google.com") }
> com.length
> }
>
> a onSuccess { case r => .... }
>
>
> - Tiark
>
>
> On Feb 16, 2012, at 1:28 AM, Daniel wrote:
>
>> Hi all
>>
>> In order to get a better understanding about delimited continuations I
>> tried to implement something akin to C# async [1]. Since I think this
>> has the potential to be cool, I share it with you. I would appreciate
>> any hints and comments.
>>
>> As a substitute for C#s Tasks I went with akka 2.0 Futures [2] since
>> those will eventually be integrated into the main library [3] afaik.
>> I have the following:
>>
>>
>> == Example ==
>>
>> context(GUI) { implicit ec =>
>> async {
>> m("1")
>>
>> val contentCom = await { dlWebSite("http://www.google.com") }
>> m("2 " + contentCom)
>>
>> val contentCh = await { dlWebSite("http://www.google.ch") }
>> m("3 " + contentCh)
>>
>> val contentDe = await { dlWebSite("http://www.google.de") }
>> m("4 " + contentDe)
>> }
>> }
>>
>> // Returns a Future which will eventually hold the downloaded html.
>> // The download itself is scheduled on a thread pool.
>> def dlWebSite(url: String): Future[String] = Future {
>> m("downloading: " + url)
>> Source.fromURL(new URL(url))
>> (Codec.ISO8859).getLines.mkString.take(20)
>> }(ThreadPool)
>>
>> // Prints msg prefixed with the name of the current thread
>> def m(msg: String) = println(Thread.currentThread().getName() + " '" +
>> msg + "'")
>>
>>
>> == Output ==
>>
>> UI '1'
>> pool-1-thread-1 'downloading: http://www.google.com'
>> UI '2 > pool-1-thread-3 'downloading: http://www.google.ch'
>> UI '3 > pool-1-thread-5 'downloading: http://www.google.de'
>> UI '4 >
>> As you can see, the hard work is executed on a thread pool but the
>> results are again on the UI thread. No blocking behind the scenes.
>>
>>
>> == Implementation ==
>>
>> // The async method is nothing more than a nice name for
>> // scala.util.continuations.reset
>> def async[B](block: => Unit@suspendable): Unit = reset[Unit,Unit]
>> { block }
>>
>> // The await method takes a block which returns a Future[A] and
>> // pretends to return an A to the caller. Without continuations, this
>> would be
>> // only possible by waiting (blocking) on the future until the result
>> is ready.
>> def await[A](block: => Future[A])(implicit ec: ExecutionContext =
>> ThreadPool): A@suspendable = shift { cont: (A => Unit) =>
>> block onSuccess { case r => ec.execute{ cont(r) } }
>> }
>>
>> // The context method is used to put an ExecutionContext into scope
>> // which runs the given block. It primarily exists to give nice
>> // looking examples.
>> def context[T](ec: ExecutionContext)(block: ExecutionContext => T)
>> { ec.execute{ block(ec) } }
>>
>> // Dummy placeholder to simulate the Swing event dispatching thread
>> val GUI =
>> ExecutionContexts.fromExecutor(Executors.newSingleThreadExecutor(
>> new ThreadFactory{ def newThread(r: Runnable): Thread = new
>> Thread(r,"UI")}))
>>
>> // Thread pool for the heavy background work
>> val ThreadPool = ExecutionContexts.fromExecutorService(
>>
>> Executors.newFixedThreadPool(10))
>>
>> // Runnables without the noise
>> implicit def toRunnable[T](f: => T ): Runnable = new Runnable { def
>> run() = f }
>>
>>
>> == The Problem ==
>>
>> I would like the async block to return a Future of its syntactic
>> return value:
>>
>> val a: Future[Int] = async[Int] {
>> m("1")
>> val com = await[String,Int,NotLast] {
>> dlWebSite("http://www.google.com")
>> }
>> m("2 " + com)
>>
>> val ch = await[String,Int,NotLast] {
>> dlWebSite("http://www.google.ch")
>> }
>> m("3 " + ch)
>>
>> val de = await[String,Int,Last] {
>> dlWebSite("http://www.google.de")
>> }
>> m("4 " + de)
>>
>> de.length() // this should be returned as a Future[Int]
>> }
>> a onSuccess { case r => m("res" + r) }
>>
>>
>> == Output ==
>>
>> UI '1'
>> pool-1-thread-1 'downloading: http://www.google.com'
>> UI '2 > pool-1-thread-3 'downloading: http://www.google.ch'
>> UI '3 > pool-1-thread-5 'downloading: http://www.google.de'
>> UI '4 > UI 'res20'
>>
>> The good part is that it works. The problem is, that now all
>> those hairy type declarations are required. I could life with
>> await[String,Int] {...} but my solution requires a further type
>> parameter to distinguish whether it is the last await in a reset
>> block or not. The last await turns the Int into a Future[Int]
>> and all awaits above that last one need to reflect this in their
>> type. Here is the code:
>>
>> // Better name for reset. Takes a block with a syntactic return type
>> // of B and returns a Future[B]
>> def async[B](block: => B@cpsParam[B,Future[B]]): Future[B] =
>> reset[B,Future[B]] { block }
>>
>> // The D[_] type parameter is required in @cpsParam.
>> // Depending on the given type the matching implicit is searched.
>> def await[A,B,D[_]] (block: => Future[A])
>> (implicit ec: ExecutionContext = ThreadPool,
>> f: (=> Future[A]) => ExecutionContext => A@cpsParam[D[B],Future[B]]
>> ):A@cpsParam[D[B],Future[B]] = f(block)(ec)
>>
>>
>> type Last[X] = X
>>
>> // The last await needs a continuation form A => Last[B] which is from
>> A => B
>> implicit def last[A,B]: (=> Future[A]) => ExecutionContext =>
>> A@cpsParam[Last[B],Future[B]] = {
>> block => ec => shift[A,Last[B],Future[B]] { cont: (A => Last[B]) =>
>> val p = Promise[B]()(ec)
>> block onSuccess { case a => ec.execute{ p.success(cont(a)) } }
>> p
>> }
>> }
>>
>> type NotLast[X] = Future[X]
>>
>> // All other awaits need a continuation from A => NotLast[B]
>> // which is from A => Future[B]
>> implicit def notLast[A,B]: (=> Future[A]) => ExecutionContext =>
>> A@cpsParam[NotLast[B],Future[B]] = {
>> block => ec => shift[A,NotLast[B],Future[B]] { cont: (A =>
>> NotLast[B]) =>
>> val p = Promise[B]()(ec)
>> block onSuccess { case a =>
>> ec.execute{ p.completeWith(cont(a)) } }
>> p
>> }
>> }
>>
>> This was the best solution I was able to come up with. Of course I
>> could offer two different await methods which would be a simple
>> solution if they had different names. But that is not an option. BTW I
>> am fully aware that the presented code has at most toy quality (
>> handles only onSuccess, etc.). Anyway, thanks for reading that far. If
>> you want to learn about scala's continuations I recommend reading this
>> blog post [4] by Jim McBeath.
>>
>> Thanks Daniel
>>
>>
>> [1] http://msdn.microsoft.com/en-us/vstudio/gg316360
>> [2] http://akka.io/docs/akka/2.0-RC1/scala/futures.html
>> [3] http://docs.scala-lang.org/sips/pending/futures-promises.html
>> [4] http://jim-mcbeath.blogspot.com/2010/08/delimited-continuations.html
>
Thu, 2012-02-16, 13:21
#3
Re: C# async implemented in scala (based on delimited continuat
Yes, the differences are minor:
def flow[A](body: => A @cps[Future[Any]]): Future[A]
def async[A](body: => A @suspendable): Future[A]
this one avoids the Future[Any] part.
- Tiark
On Feb 16, 2012, at 12:48 PM, √iktor Ҡlang wrote:
> I think we already got this covered with the dataflow API in Akka:
>
> http://akka.io/docs/akka/2.0-RC1/scala/dataflow.html
>
> Cheers,
> √
>
> On Thu, Feb 16, 2012 at 12:40 PM, Tiark Rompf wrote:
>> Sweet! Would this version of async
>>
>> def async[A](body: => A @suspendable) = {
>> val p = promise[A]
>> reset { p success body }
>> p
>> }
>>
>> work for the extended case you mention?
>>
>> val a: Future[Int] = async[Int] {
>> val com = await { dlWebSite("http://www.google.com") }
>> com.length
>> }
>>
>> a onSuccess { case r => .... }
>>
>>
>> - Tiark
>>
>>
>> On Feb 16, 2012, at 1:28 AM, Daniel wrote:
>>
>>> Hi all
>>>
>>> In order to get a better understanding about delimited continuations I
>>> tried to implement something akin to C# async [1]. Since I think this
>>> has the potential to be cool, I share it with you. I would appreciate
>>> any hints and comments.
>>>
>>> As a substitute for C#s Tasks I went with akka 2.0 Futures [2] since
>>> those will eventually be integrated into the main library [3] afaik.
>>> I have the following:
>>>
>>>
>>> == Example ==
>>>
>>> context(GUI) { implicit ec =>
>>> async {
>>> m("1")
>>>
>>> val contentCom = await { dlWebSite("http://www.google.com") }
>>> m("2 " + contentCom)
>>>
>>> val contentCh = await { dlWebSite("http://www.google.ch") }
>>> m("3 " + contentCh)
>>>
>>> val contentDe = await { dlWebSite("http://www.google.de") }
>>> m("4 " + contentDe)
>>> }
>>> }
>>>
>>> // Returns a Future which will eventually hold the downloaded html.
>>> // The download itself is scheduled on a thread pool.
>>> def dlWebSite(url: String): Future[String] = Future {
>>> m("downloading: " + url)
>>> Source.fromURL(new URL(url))
>>> (Codec.ISO8859).getLines.mkString.take(20)
>>> }(ThreadPool)
>>>
>>> // Prints msg prefixed with the name of the current thread
>>> def m(msg: String) = println(Thread.currentThread().getName() + " '" +
>>> msg + "'")
>>>
>>>
>>> == Output ==
>>>
>>> UI '1'
>>> pool-1-thread-1 'downloading: http://www.google.com'
>>> UI '2 >> pool-1-thread-3 'downloading: http://www.google.ch'
>>> UI '3 >> pool-1-thread-5 'downloading: http://www.google.de'
>>> UI '4 >>
>>> As you can see, the hard work is executed on a thread pool but the
>>> results are again on the UI thread. No blocking behind the scenes.
>>>
>>>
>>> == Implementation ==
>>>
>>> // The async method is nothing more than a nice name for
>>> // scala.util.continuations.reset
>>> def async[B](block: => Unit@suspendable): Unit = reset[Unit,Unit]
>>> { block }
>>>
>>> // The await method takes a block which returns a Future[A] and
>>> // pretends to return an A to the caller. Without continuations, this
>>> would be
>>> // only possible by waiting (blocking) on the future until the result
>>> is ready.
>>> def await[A](block: => Future[A])(implicit ec: ExecutionContext =
>>> ThreadPool): A@suspendable = shift { cont: (A => Unit) =>
>>> block onSuccess { case r => ec.execute{ cont(r) } }
>>> }
>>>
>>> // The context method is used to put an ExecutionContext into scope
>>> // which runs the given block. It primarily exists to give nice
>>> // looking examples.
>>> def context[T](ec: ExecutionContext)(block: ExecutionContext => T)
>>> { ec.execute{ block(ec) } }
>>>
>>> // Dummy placeholder to simulate the Swing event dispatching thread
>>> val GUI =
>>> ExecutionContexts.fromExecutor(Executors.newSingleThreadExecutor(
>>> new ThreadFactory{ def newThread(r: Runnable): Thread = new
>>> Thread(r,"UI")}))
>>>
>>> // Thread pool for the heavy background work
>>> val ThreadPool = ExecutionContexts.fromExecutorService(
>>>
>>> Executors.newFixedThreadPool(10))
>>>
>>> // Runnables without the noise
>>> implicit def toRunnable[T](f: => T ): Runnable = new Runnable { def
>>> run() = f }
>>>
>>>
>>> == The Problem ==
>>>
>>> I would like the async block to return a Future of its syntactic
>>> return value:
>>>
>>> val a: Future[Int] = async[Int] {
>>> m("1")
>>> val com = await[String,Int,NotLast] {
>>> dlWebSite("http://www.google.com")
>>> }
>>> m("2 " + com)
>>>
>>> val ch = await[String,Int,NotLast] {
>>> dlWebSite("http://www.google.ch")
>>> }
>>> m("3 " + ch)
>>>
>>> val de = await[String,Int,Last] {
>>> dlWebSite("http://www.google.de")
>>> }
>>> m("4 " + de)
>>>
>>> de.length() // this should be returned as a Future[Int]
>>> }
>>> a onSuccess { case r => m("res" + r) }
>>>
>>>
>>> == Output ==
>>>
>>> UI '1'
>>> pool-1-thread-1 'downloading: http://www.google.com'
>>> UI '2 >> pool-1-thread-3 'downloading: http://www.google.ch'
>>> UI '3 >> pool-1-thread-5 'downloading: http://www.google.de'
>>> UI '4 >> UI 'res20'
>>>
>>> The good part is that it works. The problem is, that now all
>>> those hairy type declarations are required. I could life with
>>> await[String,Int] {...} but my solution requires a further type
>>> parameter to distinguish whether it is the last await in a reset
>>> block or not. The last await turns the Int into a Future[Int]
>>> and all awaits above that last one need to reflect this in their
>>> type. Here is the code:
>>>
>>> // Better name for reset. Takes a block with a syntactic return type
>>> // of B and returns a Future[B]
>>> def async[B](block: => B@cpsParam[B,Future[B]]): Future[B] =
>>> reset[B,Future[B]] { block }
>>>
>>> // The D[_] type parameter is required in @cpsParam.
>>> // Depending on the given type the matching implicit is searched.
>>> def await[A,B,D[_]] (block: => Future[A])
>>> (implicit ec: ExecutionContext = ThreadPool,
>>> f: (=> Future[A]) => ExecutionContext => A@cpsParam[D[B],Future[B]]
>>> ):A@cpsParam[D[B],Future[B]] = f(block)(ec)
>>>
>>>
>>> type Last[X] = X
>>>
>>> // The last await needs a continuation form A => Last[B] which is from
>>> A => B
>>> implicit def last[A,B]: (=> Future[A]) => ExecutionContext =>
>>> A@cpsParam[Last[B],Future[B]] = {
>>> block => ec => shift[A,Last[B],Future[B]] { cont: (A => Last[B]) =>
>>> val p = Promise[B]()(ec)
>>> block onSuccess { case a => ec.execute{ p.success(cont(a)) } }
>>> p
>>> }
>>> }
>>>
>>> type NotLast[X] = Future[X]
>>>
>>> // All other awaits need a continuation from A => NotLast[B]
>>> // which is from A => Future[B]
>>> implicit def notLast[A,B]: (=> Future[A]) => ExecutionContext =>
>>> A@cpsParam[NotLast[B],Future[B]] = {
>>> block => ec => shift[A,NotLast[B],Future[B]] { cont: (A =>
>>> NotLast[B]) =>
>>> val p = Promise[B]()(ec)
>>> block onSuccess { case a =>
>>> ec.execute{ p.completeWith(cont(a)) } }
>>> p
>>> }
>>> }
>>>
>>> This was the best solution I was able to come up with. Of course I
>>> could offer two different await methods which would be a simple
>>> solution if they had different names. But that is not an option. BTW I
>>> am fully aware that the presented code has at most toy quality (
>>> handles only onSuccess, etc.). Anyway, thanks for reading that far. If
>>> you want to learn about scala's continuations I recommend reading this
>>> blog post [4] by Jim McBeath.
>>>
>>> Thanks Daniel
>>>
>>>
>>> [1] http://msdn.microsoft.com/en-us/vstudio/gg316360
>>> [2] http://akka.io/docs/akka/2.0-RC1/scala/futures.html
>>> [3] http://docs.scala-lang.org/sips/pending/futures-promises.html
>>> [4] http://jim-mcbeath.blogspot.com/2010/08/delimited-continuations.html
>>
>
>
>
Thu, 2012-02-16, 13:31
#4
Re: C# async implemented in scala (based on delimited continuat
2012/2/16 Tiark Rompf :
> Yes, the differences are minor:
>
> def flow[A](body: => A @cps[Future[Any]]): Future[A]
>
> def async[A](body: => A @suspendable): Future[A]
>
> this one avoids the Future[Any] part.
What are the pros/cons?
>
> - Tiark
>
> On Feb 16, 2012, at 12:48 PM, √iktor Ҡlang wrote:
>
>> I think we already got this covered with the dataflow API in Akka:
>>
>> http://akka.io/docs/akka/2.0-RC1/scala/dataflow.html
>>
>> Cheers,
>> √
>>
>> On Thu, Feb 16, 2012 at 12:40 PM, Tiark Rompf wrote:
>>> Sweet! Would this version of async
>>>
>>> def async[A](body: => A @suspendable) = {
>>> val p = promise[A]
>>> reset { p success body }
>>> p
>>> }
>>>
>>> work for the extended case you mention?
>>>
>>> val a: Future[Int] = async[Int] {
>>> val com = await { dlWebSite("http://www.google.com") }
>>> com.length
>>> }
>>>
>>> a onSuccess { case r => .... }
>>>
>>>
>>> - Tiark
>>>
>>>
>>> On Feb 16, 2012, at 1:28 AM, Daniel wrote:
>>>
>>>> Hi all
>>>>
>>>> In order to get a better understanding about delimited continuations I
>>>> tried to implement something akin to C# async [1]. Since I think this
>>>> has the potential to be cool, I share it with you. I would appreciate
>>>> any hints and comments.
>>>>
>>>> As a substitute for C#s Tasks I went with akka 2.0 Futures [2] since
>>>> those will eventually be integrated into the main library [3] afaik.
>>>> I have the following:
>>>>
>>>>
>>>> == Example ==
>>>>
>>>> context(GUI) { implicit ec =>
>>>> async {
>>>> m("1")
>>>>
>>>> val contentCom = await { dlWebSite("http://www.google.com") }
>>>> m("2 " + contentCom)
>>>>
>>>> val contentCh = await { dlWebSite("http://www.google.ch") }
>>>> m("3 " + contentCh)
>>>>
>>>> val contentDe = await { dlWebSite("http://www.google.de") }
>>>> m("4 " + contentDe)
>>>> }
>>>> }
>>>>
>>>> // Returns a Future which will eventually hold the downloaded html.
>>>> // The download itself is scheduled on a thread pool.
>>>> def dlWebSite(url: String): Future[String] = Future {
>>>> m("downloading: " + url)
>>>> Source.fromURL(new URL(url))
>>>> (Codec.ISO8859).getLines.mkString.take(20)
>>>> }(ThreadPool)
>>>>
>>>> // Prints msg prefixed with the name of the current thread
>>>> def m(msg: String) = println(Thread.currentThread().getName() + " '" +
>>>> msg + "'")
>>>>
>>>>
>>>> == Output ==
>>>>
>>>> UI '1'
>>>> pool-1-thread-1 'downloading: http://www.google.com'
>>>> UI '2 >>> pool-1-thread-3 'downloading: http://www.google.ch'
>>>> UI '3 >>> pool-1-thread-5 'downloading: http://www.google.de'
>>>> UI '4 >>>
>>>> As you can see, the hard work is executed on a thread pool but the
>>>> results are again on the UI thread. No blocking behind the scenes.
>>>>
>>>>
>>>> == Implementation ==
>>>>
>>>> // The async method is nothing more than a nice name for
>>>> // scala.util.continuations.reset
>>>> def async[B](block: => Unit@suspendable): Unit = reset[Unit,Unit]
>>>> { block }
>>>>
>>>> // The await method takes a block which returns a Future[A] and
>>>> // pretends to return an A to the caller. Without continuations, this
>>>> would be
>>>> // only possible by waiting (blocking) on the future until the result
>>>> is ready.
>>>> def await[A](block: => Future[A])(implicit ec: ExecutionContext =
>>>> ThreadPool): A@suspendable = shift { cont: (A => Unit) =>
>>>> block onSuccess { case r => ec.execute{ cont(r) } }
>>>> }
>>>>
>>>> // The context method is used to put an ExecutionContext into scope
>>>> // which runs the given block. It primarily exists to give nice
>>>> // looking examples.
>>>> def context[T](ec: ExecutionContext)(block: ExecutionContext => T)
>>>> { ec.execute{ block(ec) } }
>>>>
>>>> // Dummy placeholder to simulate the Swing event dispatching thread
>>>> val GUI =
>>>> ExecutionContexts.fromExecutor(Executors.newSingleThreadExecutor(
>>>> new ThreadFactory{ def newThread(r: Runnable): Thread = new
>>>> Thread(r,"UI")}))
>>>>
>>>> // Thread pool for the heavy background work
>>>> val ThreadPool = ExecutionContexts.fromExecutorService(
>>>>
>>>> Executors.newFixedThreadPool(10))
>>>>
>>>> // Runnables without the noise
>>>> implicit def toRunnable[T](f: => T ): Runnable = new Runnable { def
>>>> run() = f }
>>>>
>>>>
>>>> == The Problem ==
>>>>
>>>> I would like the async block to return a Future of its syntactic
>>>> return value:
>>>>
>>>> val a: Future[Int] = async[Int] {
>>>> m("1")
>>>> val com = await[String,Int,NotLast] {
>>>> dlWebSite("http://www.google.com")
>>>> }
>>>> m("2 " + com)
>>>>
>>>> val ch = await[String,Int,NotLast] {
>>>> dlWebSite("http://www.google.ch")
>>>> }
>>>> m("3 " + ch)
>>>>
>>>> val de = await[String,Int,Last] {
>>>> dlWebSite("http://www.google.de")
>>>> }
>>>> m("4 " + de)
>>>>
>>>> de.length() // this should be returned as a Future[Int]
>>>> }
>>>> a onSuccess { case r => m("res" + r) }
>>>>
>>>>
>>>> == Output ==
>>>>
>>>> UI '1'
>>>> pool-1-thread-1 'downloading: http://www.google.com'
>>>> UI '2 >>> pool-1-thread-3 'downloading: http://www.google.ch'
>>>> UI '3 >>> pool-1-thread-5 'downloading: http://www.google.de'
>>>> UI '4 >>> UI 'res20'
>>>>
>>>> The good part is that it works. The problem is, that now all
>>>> those hairy type declarations are required. I could life with
>>>> await[String,Int] {...} but my solution requires a further type
>>>> parameter to distinguish whether it is the last await in a reset
>>>> block or not. The last await turns the Int into a Future[Int]
>>>> and all awaits above that last one need to reflect this in their
>>>> type. Here is the code:
>>>>
>>>> // Better name for reset. Takes a block with a syntactic return type
>>>> // of B and returns a Future[B]
>>>> def async[B](block: => B@cpsParam[B,Future[B]]): Future[B] =
>>>> reset[B,Future[B]] { block }
>>>>
>>>> // The D[_] type parameter is required in @cpsParam.
>>>> // Depending on the given type the matching implicit is searched.
>>>> def await[A,B,D[_]] (block: => Future[A])
>>>> (implicit ec: ExecutionContext = ThreadPool,
>>>> f: (=> Future[A]) => ExecutionContext => A@cpsParam[D[B],Future[B]]
>>>> ):A@cpsParam[D[B],Future[B]] = f(block)(ec)
>>>>
>>>>
>>>> type Last[X] = X
>>>>
>>>> // The last await needs a continuation form A => Last[B] which is from
>>>> A => B
>>>> implicit def last[A,B]: (=> Future[A]) => ExecutionContext =>
>>>> A@cpsParam[Last[B],Future[B]] = {
>>>> block => ec => shift[A,Last[B],Future[B]] { cont: (A => Last[B]) =>
>>>> val p = Promise[B]()(ec)
>>>> block onSuccess { case a => ec.execute{ p.success(cont(a)) } }
>>>> p
>>>> }
>>>> }
>>>>
>>>> type NotLast[X] = Future[X]
>>>>
>>>> // All other awaits need a continuation from A => NotLast[B]
>>>> // which is from A => Future[B]
>>>> implicit def notLast[A,B]: (=> Future[A]) => ExecutionContext =>
>>>> A@cpsParam[NotLast[B],Future[B]] = {
>>>> block => ec => shift[A,NotLast[B],Future[B]] { cont: (A =>
>>>> NotLast[B]) =>
>>>> val p = Promise[B]()(ec)
>>>> block onSuccess { case a =>
>>>> ec.execute{ p.completeWith(cont(a)) } }
>>>> p
>>>> }
>>>> }
>>>>
>>>> This was the best solution I was able to come up with. Of course I
>>>> could offer two different await methods which would be a simple
>>>> solution if they had different names. But that is not an option. BTW I
>>>> am fully aware that the presented code has at most toy quality (
>>>> handles only onSuccess, etc.). Anyway, thanks for reading that far. If
>>>> you want to learn about scala's continuations I recommend reading this
>>>> blog post [4] by Jim McBeath.
>>>>
>>>> Thanks Daniel
>>>>
>>>>
>>>> [1] http://msdn.microsoft.com/en-us/vstudio/gg316360
>>>> [2] http://akka.io/docs/akka/2.0-RC1/scala/futures.html
>>>> [3] http://docs.scala-lang.org/sips/pending/futures-promises.html
>>>> [4] http://jim-mcbeath.blogspot.com/2010/08/delimited-continuations.html
>>>
>>
>>
>>
>> --
>> Viktor Klang
>>
>> Akka Tech Lead
>> Typesafe - The software stack for applications that scale
>>
>> Twitter: @viktorklang
>
Thu, 2012-02-16, 15:31
#5
Re: C# async implemented in scala (based on delimited continuati
Hi Tiark
> Sweet! Would this version of async
>
> def async[A](body: => A @suspendable) = {
> val p = promise[A]
> reset { p success body }
> p
> }
>
> work for the extended case you mention?
Yes it does. I really should have asked earlier =) Many thanks for
this simple solution!
def async[A](body: => A @suspendable): Future[A] = {
val p = Promise[A]()
reset { p success body; () } // The '()' is required for
successful type inference
p
}
def await[A](block: => Future[A])(implicit ec: ExecutionContext):
A@suspendable = shift { cont: (A => Unit) =>
block onSuccess { case r => ec.execute{ cont(r) } }
}
Cheers Daniel
///////////////////////////////// full
example ////////////////////////////
import scala.util.continuations._
import akka.dispatch._
import java.util.concurrent.Executors
import java.net.URL
import java.util.concurrent.ThreadFactory
object TiarkExample extends App {
implicit def toRunnable[T](f: => T): Runnable = new Runnable { def
run() = f }
implicit val GUI =
ExecutionContexts.fromExecutor(Executors.newSingleThreadExecutor(new
ThreadFactory{ def newThread(r: Runnable): Thread = new
Thread(r,"UI")}))
val POOL =
ExecutionContexts.fromExecutor(Executors.newFixedThreadPool(2))
def async[A](body: => A @suspendable): Future[A] = {
val p = Promise[A]()
reset { p success body; () }
p
}
def await[A](block: => Future[A])(implicit ec: ExecutionContext):
A@suspendable = shift { cont: (A => Unit) =>
block onSuccess { case r => ec.execute{ cont(r) } }
}
val a = async {
m("1")
val com = await { downloadWebSiteTask("http://www.google.com")}
m("2")
val ch = await { downloadWebSiteTask("http://www.google.ch")}
m("3")
ch.length + com.length
}
a onSuccess { case r => m("result: " + r)}
def downloadWebSiteTask(url: String): Future[String] = Future {
m("downloading: " + url)
io.Source.fromURL(new URL(url))
(io.Codec.ISO8859).getLines.mkString.take(20)
}(POOL)
def m(msg: String) = println(Thread.currentThread().getName() + " '"
+ msg + "'")
}
Thu, 2012-02-16, 15:41
#6
Re: C# async implemented in scala (based on delimited continuati
Hi Victor
> I think we already got this covered with the dataflow API in Akka:
Right! I just tried it:
val a = flow {
m("1")
val com = downloadWebSiteTask("http://www.google.com")()
m("2")
val ch = downloadWebSiteTask("http://www.google.ch")()
m("3")
ch.length + com.length
}
a onSuccess { case r => m("result: " + r)}
Output:
UI '1'
pool-1-thread-1 'downloading: http://www.google.com'
pool-1-thread-2 '2' HERE
pool-1-thread-1 'downloading: http://www.google.ch'
pool-1-thread-1 '3' HERE
pool-1-thread-1 'result: 40' HERE
What would I have to do if I need the 'callbacks' to be executed on
the implicit ExecutionContext (the one that flow{..}(ctx) captures)?
Daniel
Thu, 2012-02-16, 15:51
#7
Re: Re: C# async implemented in scala (based on delimited conti
On Thu, Feb 16, 2012 at 3:34 PM, Daniel wrote:
> Hi Victor
>
>> I think we already got this covered with the dataflow API in Akka:
>
> Right! I just tried it:
>
> val a = flow {
> m("1")
> val com = downloadWebSiteTask("http://www.google.com")()
> m("2")
> val ch = downloadWebSiteTask("http://www.google.ch")()
> m("3")
> ch.length + com.length
> }
> a onSuccess { case r => m("result: " + r)}
>
> Output:
>
> UI '1'
> pool-1-thread-1 'downloading: http://www.google.com'
> pool-1-thread-2 '2' HERE
> pool-1-thread-1 'downloading: http://www.google.ch'
> pool-1-thread-1 '3' HERE
> pool-1-thread-1 'result: 40' HERE
>
> What would I have to do if I need the 'callbacks' to be executed on
> the implicit ExecutionContext (the one that flow{..}(ctx) captures)?
That's a good one! Let me see what we can do about that.
Cheers,
√
>
> Daniel
Thu, 2012-02-16, 16:01
#8
Re: Re: C# async implemented in scala (based on delimited conti
Hi Victor
This is maybe also worth a discussion:
def namedCtx(n: String) = ExecutionContexts.fromExecutor(
Executors.newSingleThreadExecutor( new ThreadFactory {
def newThread(r: Runnable) = new Thread(r,n)
}))
val A = namedCtx("A")
val B = namedCtx("B")
// create a promise with ctx A
val p = Promise[String]()(A)
// I would expect that any callback from p
// is executed in the context of p
p onSuccess{
case r => println(Thread.currentThread().getName() + " " + r)
}
p.completeWith(Future{"Hi"}(B))
The above prints "B Hi"
What do you think?
Thu, 2012-02-16, 16:11
#9
Re: Re: C# async implemented in scala (based on delimited conti
Hi Daniel,
2012/2/16 Daniel Kröni :
> Hi Victor
>
> This is maybe also worth a discussion:
>
> def namedCtx(n: String) = ExecutionContexts.fromExecutor(
> Executors.newSingleThreadExecutor( new ThreadFactory {
> def newThread(r: Runnable) = new Thread(r,n)
> }))
>
> val A = namedCtx("A")
> val B = namedCtx("B")
>
> // create a promise with ctx A
> val p = Promise[String]()(A)
>
> // I would expect that any callback from p
> // is executed in the context of p
> p onSuccess{
> case r => println(Thread.currentThread().getName() + " " + r)
> }
>
> p.completeWith(Future{"Hi"}(B))
>
> The above prints "B Hi"
>
> What do you think?
final def completeWith(other: Future[T]): this.type = {
other onComplete { tryComplete(_) }
this
}
Cheers,
√
Thu, 2012-02-16, 16:41
#10
Re: C# async implemented in scala (based on delimited continuat
2012/2/16 √iktor Ҡlang <viktor.klang@gmail.com>
They handle exceptions differently. 'flow' propagates the exception through the futures, and it looks like 'async' ignores it (although some cases could probably be implemented).
I originally did 'flow' with @suspendable, but there was a situation where I just couldn't get the exception to continue through, causing the final future to timeout. I think it had something to do with having the type inferred as a Future[Nothing] (back in the olden days).
--
Derek Williams
2012/2/16 Tiark Rompf <tiark.rompf@epfl.ch>:
> Yes, the differences are minor:
>
> def flow[A](body: => A @cps[Future[Any]]): Future[A]
>
> def async[A](body: => A @suspendable): Future[A]
>
> this one avoids the Future[Any] part.
What are the pros/cons?
They handle exceptions differently. 'flow' propagates the exception through the futures, and it looks like 'async' ignores it (although some cases could probably be implemented).
I originally did 'flow' with @suspendable, but there was a situation where I just couldn't get the exception to continue through, causing the final future to timeout. I think it had something to do with having the type inferred as a Future[Nothing] (back in the olden days).
--
Derek Williams
Thu, 2012-02-16, 23:21
#11
Re: C# async implemented in scala (based on delimited continuati
Hi Derek, All
> They handle exceptions differently. 'flow' propagates the exception through
> the futures, and it looks like 'async' ignores it (although some cases
> could probably be implemented).
I implement some exception handling [1] and polished the example [2].
Any comments?
Thanks Daniel
[1] https://github.com/danielkroeni/scala-async/blob/master/src/main/scala/a...
[2] https://github.com/danielkroeni/scala-async/blob/master/src/main/scala/a...
Sat, 2012-02-18, 00:31
#12
Re: Re: C# async implemented in scala (based on delimited conti
I have been trying to follow this discussion, as it really
fascinates me, and while I get the gist of it, I cannot grok it.
I still struggle with continuations in Scala
I would appreciate it if someone could take the time explain what is going on in this particular discussion as I do find it fascinating.
Cheers, Eric
I still struggle with continuations in Scala
- I have never been able to get them to work in the
Eclipse/Scala environment. It would be nice if they could 'just
work' - but they don't. Consequently I cannot even play with
them.
- I have not internalized the concepts the way one would internalize say recursion or closures.
I would appreciate it if someone could take the time explain what is going on in this particular discussion as I do find it fascinating.
Cheers, Eric
Sat, 2012-02-18, 09:41
#13
Re: Re: C# async implemented in scala (based on delimited conti
Hmm, did you develop in JS? Closures everywhere.
Thanks,
-Vlad
On Fri, Feb 17, 2012 at 3:23 PM, Eric Kolotyluk <eric.kolotyluk@gmail.com> wrote:
Thanks,
-Vlad
On Fri, Feb 17, 2012 at 3:23 PM, Eric Kolotyluk <eric.kolotyluk@gmail.com> wrote:
I have been trying to follow this discussion, as it really fascinates me, and while I get the gist of it, I cannot grok it.
I still struggle with continuations in Scala
I have an interest in continuations particularly in the context of being able to write UI code that can only run on a single thread, but has to interact with background tasks and asynchronous activities.
- I have never been able to get them to work in the Eclipse/Scala environment. It would be nice if they could 'just work' - but they don't. Consequently I cannot even play with them.
- I have not internalized the concepts the way one would internalize say recursion or closures.
I would appreciate it if someone could take the time explain what is going on in this particular discussion as I do find it fascinating.
Cheers, Eric
Sat, 2012-02-18, 16:11
#14
Re: C# async implemented in scala (based on delimited continuati
Have you in Eclipse entered continuations:enable in the P textbox?
You can find it in Preferences > Scala > Compiler on the Standard tab
Maybe you have to clean you project too (if you have a false
NoSuchMethod error bugging you).
That is all there is. (No Xplugin path to continuations.jar necessary
on the Advanced tab, someone suggested that in scala-ide bugreport,
but I don't have it and it works too)
Create a scala project
This code works with scala-ide
Main.scala
==========
import scala.util.continuations._
object Main extends App {
def is123(n:Int):Boolean = {
reset {
shift { k : (Int=>String) =>
(k(n) == "123")
}.toString
}
}
println("the result is " +
reset {
shift { k: (Int=>Int) =>
k(k(k(7)))
} + 1
})
println("123 == 123? result is " + is123(123))
println("567 == 123? result is " + is123(567))
}
Output:
======
the result is 10
123 == 123? result is true
567 == 123? result is false
On 18 feb, 00:23, Eric Kolotyluk wrote:
> I have been trying to follow this discussion, as it really fascinates
> me, and while I get the gist of it, I cannot grok it.
>
> I still struggle with continuations in Scala
>
> 1. I have never been able to get them to work in the Eclipse/Scala
> environment. It would be nice if they could 'just work' - but they
> don't. Consequently I cannot even play with them.
> 2. I have not internalized the concepts the way one would internalize
> say recursion or closures.
>
> I have an interest in continuations particularly in the context of being
> able to write UI code that can only run on a single thread, but has to
> interact with background tasks and asynchronous activities.
>
> I would appreciate it if someone could take the time explain what is
> going on in this particular discussion as I do find it fascinating.
>
> Cheers, Eric
Sat, 2012-02-18, 16:21
#15
Re: C# async implemented in scala (based on delimited continuati
Interesting link about Swarm + Scala Delimited Continuations:
Sun, 2012-02-19, 06:01
#16
Re: Re: C# async implemented in scala (based on delimited conti
What is JS?
Cheers, Eric
On 2012-02-18 12:39 AM, Vlad Patryshev wrote:
Cheers, Eric
On 2012-02-18 12:39 AM, Vlad Patryshev wrote:
iUyp809vgnJn_aA-+d0WBWN1h3mBAEE+cx-LQ [at] mail [dot] gmail [dot] com" type="cite">Hmm, did you develop in JS? Closures everywhere.
Thanks,
-Vlad
On Fri, Feb 17, 2012 at 3:23 PM, Eric Kolotyluk <eric [dot] kolotyluk [at] gmail [dot] com" rel="nofollow">eric.kolotyluk@gmail.com> wrote:
I have been trying to follow this discussion, as it really fascinates me, and while I get the gist of it, I cannot grok it.
I still struggle with continuations in Scala
I have an interest in continuations particularly in the context of being able to write UI code that can only run on a single thread, but has to interact with background tasks and asynchronous activities.
- I have never been able to get them to work in the Eclipse/Scala environment. It would be nice if they could 'just work' - but they don't. Consequently I cannot even play with them.
- I have not internalized the concepts the way one would internalize say recursion or closures.
I would appreciate it if someone could take the time explain what is going on in this particular discussion as I do find it fascinating.
Cheers, Eric
Sun, 2012-02-19, 16:01
#17
Re: Re: C# async implemented in scala (based on delimited conti
You might consider using AsyncScala library for the task. Then annonce on LtU was:
http://lambda-the-ultimate.org/node/4289
It has explicit support for E-style actor-based programming over GUI event loop and much more (like RX-like event streams). There even samples related to it. Out-of-the box AWT event loop is supported. But adding support for SWT, should be very easy.
Thanks,Constantine
On Sat, Feb 18, 2012 at 3:23 AM, Eric Kolotyluk <eric.kolotyluk@gmail.com> wrote:
It has explicit support for E-style actor-based programming over GUI event loop and much more (like RX-like event streams). There even samples related to it. Out-of-the box AWT event loop is supported. But adding support for SWT, should be very easy.
Thanks,Constantine
On Sat, Feb 18, 2012 at 3:23 AM, Eric Kolotyluk <eric.kolotyluk@gmail.com> wrote:
I have been trying to follow this discussion, as it really fascinates me, and while I get the gist of it, I cannot grok it.
I still struggle with continuations in Scala
I have an interest in continuations particularly in the context of being able to write UI code that can only run on a single thread, but has to interact with background tasks and asynchronous activities.
- I have never been able to get them to work in the Eclipse/Scala environment. It would be nice if they could 'just work' - but they don't. Consequently I cannot even play with them.
- I have not internalized the concepts the way one would internalize say recursion or closures.
I would appreciate it if someone could take the time explain what is going on in this particular discussion as I do find it fascinating.
Cheers, Eric
Sun, 2012-02-19, 16:21
#18
Re: C# async implemented in scala (based on delimited continuati
Hi Eric
I really recommend reading the blog post by Jim McBeath [1]. I will
not be able to give a better explanation. But I will try to explain
how delimited continuations can be used to simplify asynchronous
programming.
Consider the following code fragment:
reset {
VAL A: A = shift { cont: (A => B) =>
// do something with cont.
}
VAL B: B = ...
B
}
println("after reset")
The code will be transformed in a way, that everything between shift
and the end of reset (all in UPPERcase) will be passed as the function
'cont' to shift. In other words: The uppercase part becomes the
function cont. Compare how the type of cont (A => B) aligns exactly
with the uppercase part.
After the transformation you have a situation similar to the following
where 'cont' is the upper-case part.
{ cont: (A => B) =>
// do something with cont.
}
println("after reset")
If you don't call the cont function, the uppercase part will not be
executed at all and control flow goes on with the part which was
originally after the reset block. If you call the cont function, it
will execute the uppercase part.
Let's see how we can use this for asynchronous programming:
reset {
val s: String = reset { cont: (String => Unit) =>
new Thread() {
def run {
val news = downloadNews("www.cnn.com")
cont(news) // call the cont with the result
}
}.start
}
println("news: " + s)
}
println("after reset")
In the above fragment, the call to reset returns after the new
background thread has been created and started. It will immediately
print "after reset". In the meantime the background thread loaded the
news from a webservice. Now it will call 'cont' with the downloaded
news. The val s will get assigned to the news argument passed to cont
and "news: ..." will be printed.
Instead of calling cont(news) in the background thread, one can use
for example SwingHelper to execute the 'cont' on the Swing EDT.
reset {
val s: String = reset { cont: (String => Unit) =>
new Thread() {
def run {
val news = downloadNews("www.cnn.com")
SwingUtilities.invokeLater(new Runnable { def run
{ cont(news)} })
}
}.start
}
println("news: " + s)
}
In the above code, the continuation 'cont' will be called on the Swing
thread. This means that println("news: " + s) will be executed on the
swing thread. You could directly assign the s to a Swing Textbox or
similar.
Not sure if this helps.
Cheers
Daniel
[1] http://jim-mcbeath.blogspot.com/2010/08/delimited-continuations.html
On Feb 18, 12:23 am, Eric Kolotyluk wrote:
> I have been trying to follow this discussion, as it really fascinates
> me, and while I get the gist of it, I cannot grok it.
>
> I still struggle with continuations in Scala
>
> 1. I have never been able to get them to work in the Eclipse/Scala
> environment. It would be nice if they could 'just work' - but they
> don't. Consequently I cannot even play with them.
> 2. I have not internalized the concepts the way one would internalize
> say recursion or closures.
>
> I have an interest in continuations particularly in the context of being
> able to write UI code that can only run on a single thread, but has to
> interact with background tasks and asynchronous activities.
>
> I would appreciate it if someone could take the time explain what is
> going on in this particular discussion as I do find it fascinating.
>
> Cheers, Eric
Sun, 2012-02-19, 17:11
#19
Re: Re: C# async implemented in scala (based on delimited conti
The Eclipse IDE shows
bad option: -P:continuations:enable
On 2012-02-18 7:04 AM, Dave wrote:
> Have you in Eclipse entered continuations:enable in the P textbox?
> You can find it in Preferences> Scala> Compiler on the Standard tab
>
> Maybe you have to clean you project too (if you have a false
> NoSuchMethod error bugging you).
>
> That is all there is. (No Xplugin path to continuations.jar necessary
> on the Advanced tab, someone suggested that in scala-ide bugreport,
> but I don't have it and it works too)
>
> Create a scala project
>
> This code works with scala-ide
>
> Main.scala
> ==========
> import scala.util.continuations._
>
> object Main extends App {
>
> def is123(n:Int):Boolean = {
> reset {
> shift { k : (Int=>String) =>
> (k(n) == "123")
> }.toString
> }
> }
>
> println("the result is " +
> reset {
> shift { k: (Int=>Int) =>
> k(k(k(7)))
> } + 1
> })
>
> println("123 == 123? result is " + is123(123))
> println("567 == 123? result is " + is123(567))
> }
>
>
> Output:
> ======
>
> the result is 10
> 123 == 123? result is true
> 567 == 123? result is false
>
>
>
>
>
> On 18 feb, 00:23, Eric Kolotyluk wrote:
>> I have been trying to follow this discussion, as it really fascinates
>> me, and while I get the gist of it, I cannot grok it.
>>
>> I still struggle with continuations in Scala
>>
>> 1. I have never been able to get them to work in the Eclipse/Scala
>> environment. It would be nice if they could 'just work' - but they
>> don't. Consequently I cannot even play with them.
>> 2. I have not internalized the concepts the way one would internalize
>> say recursion or closures.
>>
>> I have an interest in continuations particularly in the context of being
>> able to write UI code that can only run on a single thread, but has to
>> interact with background tasks and asynchronous activities.
>>
>> I would appreciate it if someone could take the time explain what is
>> going on in this particular discussion as I do find it fascinating.
>>
>> Cheers, Eric
Sun, 2012-02-19, 17:11
#20
Re: C# async implemented in scala (based on delimited continuati
> That is all there is. (No Xplugin path to continuations.jar necessary
> on the Advanced tab, someone suggested that in scala-ide bugreport,
> but I don't have it and it works too)
After retesting today it seems that the reference to continuations.jar
is necessary
So on Advanced tab Textbox Xplugin enter the path to continuations.jar
e.g.
C:\scala-2.9.1.final\misc\scala-devel\plugins\continuations.jar
Sun, 2012-02-19, 17:31
#21
Re: C# async implemented in scala (based on delimited continuati
Hi Daniel, the second reset should be a shift and run should have an
override keyword>
I add it to the previous example:
import scala.util.continuations._
object Main extends App {
def is123(n:Int):Boolean = {
reset {
shift { k : (Int=>String) =>
(k(n) == "123")
}.toString
}
}
def downloadNews(s: String) = { Thread.sleep(5000); "cnn news
headlines" }
reset {
val s: String = shift { cont: (String => Unit) =>
new Thread() {
override def run {
val news = downloadNews("www.cnn.com")
cont(news)
}
}.start
}
println("news: " + s)
}
println("after reset")
println("the result is " +
reset {
shift { k: (Int=>Int) =>
k(k(k(7)))
} + 1
})
println("123 == 123? result is " + is123(123))
println("567 == 123? result is " + is123(567))
}
Output:
after reset
the result is 10
123 == 123? result is true
567 == 123? result is false
news: cnn news headlines
and the last line shows up after 5 seconds
On 19 feb, 16:17, Daniel wrote:
> Hi Eric
>
> I really recommend reading the blog post by Jim McBeath [1]. I will
> not be able to give a better explanation. But I will try to explain
> how delimited continuations can be used to simplify asynchronous
> programming.
>
> Consider the following code fragment:
>
> reset {
> VAL A: A = shift { cont: (A => B) =>
> // do something with cont.
> }
> VAL B: B = ...
> B}
>
> println("after reset")
>
> The code will be transformed in a way, that everything between shift
> and the end of reset (all in UPPERcase) will be passed as the function
> 'cont' to shift. In other words: The uppercase part becomes the
> function cont. Compare how the type of cont (A => B) aligns exactly
> with the uppercase part.
>
> After the transformation you have a situation similar to the following
> where 'cont' is the upper-case part.
>
> { cont: (A => B) =>
> // do something with cont.}
>
> println("after reset")
>
> If you don't call the cont function, the uppercase part will not be
> executed at all and control flow goes on with the part which was
> originally after the reset block. If you call the cont function, it
> will execute the uppercase part.
>
> Let's see how we can use this for asynchronous programming:
>
> reset {
> val s: String = reset { cont: (String => Unit) =>
> new Thread() {
> def run {
> val news = downloadNews("www.cnn.com")
> cont(news) // call the cont with the result
> }
> }.start
> }
> println("news: " + s)}
>
> println("after reset")
>
> In the above fragment, the call to reset returns after the new
> background thread has been created and started. It will immediately
> print "after reset". In the meantime the background thread loaded the
> news from a webservice. Now it will call 'cont' with the downloaded
> news. The val s will get assigned to the news argument passed to cont
> and "news: ..." will be printed.
>
> Instead of calling cont(news) in the background thread, one can use
> for example SwingHelper to execute the 'cont' on the Swing EDT.
>
> reset {
> val s: String = reset { cont: (String => Unit) =>
> new Thread() {
> def run {
> val news = downloadNews("www.cnn.com")
> SwingUtilities.invokeLater(new Runnable { def run
> { cont(news)} })
> }
> }.start
> }
> println("news: " + s)
>
> }
>
> In the above code, the continuation 'cont' will be called on the Swing
> thread. This means that println("news: " + s) will be executed on the
> swing thread. You could directly assign the s to a Swing Textbox or
> similar.
>
> Not sure if this helps.
>
> Cheers
> Daniel
>
> [1]http://jim-mcbeath.blogspot.com/2010/08/delimited-continuations.html
>
> On Feb 18, 12:23 am, Eric Kolotyluk wrote:
>
>
>
> > I have been trying to follow this discussion, as it really fascinates
> > me, and while I get the gist of it, I cannot grok it.
>
> > I still struggle with continuations in Scala
>
> > 1. I have never been able to get them to work in the Eclipse/Scala
> > environment. It would be nice if they could 'just work' - but they
> > don't. Consequently I cannot even play with them.
> > 2. I have not internalized the concepts the way one would internalize
> > say recursion or closures.
>
> > I have an interest in continuations particularly in the context of being
> > able to write UI code that can only run on a single thread, but has to
> > interact with background tasks and asynchronous activities.
>
> > I would appreciate it if someone could take the time explain what is
> > going on in this particular discussion as I do find it fascinating.
>
> > Cheers, Eric- Tekst uit oorspronkelijk bericht niet weergeven -
>
> - Tekst uit oorspronkelijk bericht weergeven -
Sun, 2012-02-19, 17:41
#22
Re: C# async implemented in scala (based on delimited continuati
You shouldn't use -P:
only
continuations:enable
On 19 feb, 17:03, Eric Kolotyluk wrote:
> The Eclipse IDE shows
>
> bad option: -P:continuations:enable
>
> On 2012-02-18 7:04 AM, Dave wrote:
>
>
>
> > Have you in Eclipse entered continuations:enable in the P textbox?
> > You can find it in Preferences> Scala> Compiler on the Standard tab
>
> > Maybe you have to clean you project too (if you have a false
> > NoSuchMethod error bugging you).
>
> > That is all there is. (No Xplugin path to continuations.jar necessary
> > on the Advanced tab, someone suggested that in scala-ide bugreport,
> > but I don't have it and it works too)
>
> > Create a scala project
>
> > This code works with scala-ide
>
> > Main.scala
> > ==========
> > import scala.util.continuations._
>
> > object Main extends App {
>
> > def is123(n:Int):Boolean = {
> > reset {
> > shift { k : (Int=>String) =>
> > (k(n) == "123")
> > }.toString
> > }
> > }
>
> > println("the result is " +
> > reset {
> > shift { k: (Int=>Int) =>
> > k(k(k(7)))
> > } + 1
> > })
>
> > println("123 == 123? result is " + is123(123))
> > println("567 == 123? result is " + is123(567))
> > }
>
> > Output:
> > ======
>
> > the result is 10
> > 123 == 123? result is true
> > 567 == 123? result is false
>
> > On 18 feb, 00:23, Eric Kolotyluk wrote:
> >> I have been trying to follow this discussion, as it really fascinates
> >> me, and while I get the gist of it, I cannot grok it.
>
> >> I still struggle with continuations in Scala
>
> >> 1. I have never been able to get them to work in the Eclipse/Scala
> >> environment. It would be nice if they could 'just work' - but they
> >> don't. Consequently I cannot even play with them.
> >> 2. I have not internalized the concepts the way one would internalize
> >> say recursion or closures.
>
> >> I have an interest in continuations particularly in the context of being
> >> able to write UI code that can only run on a single thread, but has to
> >> interact with background tasks and asynchronous activities.
>
> >> I would appreciate it if someone could take the time explain what is
> >> going on in this particular discussion as I do find it fascinating.
>
> >> Cheers, Eric- Tekst uit oorspronkelijk bericht niet weergeven -
>
> - Tekst uit oorspronkelijk bericht weergeven -
Mon, 2012-02-20, 13:31
#23
Re: C# async implemented in scala (based on delimited continuati
Maybe you have Use Project Properties enabled
Then you can fill them in on project level in Project > Properties >
Scala Compiler
and clean project before running
On 19 feb, 17:03, Eric Kolotyluk wrote:
> The Eclipse IDE shows
>
> bad option: -P:continuations:enable
>
> On 2012-02-18 7:04 AM, Dave wrote:
>
>
>
> > Have you in Eclipse entered continuations:enable in the P textbox?
> > You can find it in Preferences> Scala> Compiler on the Standard tab
>
> > Maybe you have to clean you project too (if you have a false
> > NoSuchMethod error bugging you).
>
> > That is all there is. (No Xplugin path to continuations.jar necessary
> > on the Advanced tab, someone suggested that in scala-ide bugreport,
> > but I don't have it and it works too)
>
> > Create a scala project
>
> > This code works with scala-ide
>
> > Main.scala
> > ==========
> > import scala.util.continuations._
>
> > object Main extends App {
>
> > def is123(n:Int):Boolean = {
> > reset {
> > shift { k : (Int=>String) =>
> > (k(n) == "123")
> > }.toString
> > }
> > }
>
> > println("the result is " +
> > reset {
> > shift { k: (Int=>Int) =>
> > k(k(k(7)))
> > } + 1
> > })
>
> > println("123 == 123? result is " + is123(123))
> > println("567 == 123? result is " + is123(567))
> > }
>
> > Output:
> > ======
>
> > the result is 10
> > 123 == 123? result is true
> > 567 == 123? result is false
>
> > On 18 feb, 00:23, Eric Kolotyluk wrote:
> >> I have been trying to follow this discussion, as it really fascinates
> >> me, and while I get the gist of it, I cannot grok it.
>
> >> I still struggle with continuations in Scala
>
> >> 1. I have never been able to get them to work in the Eclipse/Scala
> >> environment. It would be nice if they could 'just work' - but they
> >> don't. Consequently I cannot even play with them.
> >> 2. I have not internalized the concepts the way one would internalize
> >> say recursion or closures.
>
> >> I have an interest in continuations particularly in the context of being
> >> able to write UI code that can only run on a single thread, but has to
> >> interact with background tasks and asynchronous activities.
>
> >> I would appreciate it if someone could take the time explain what is
> >> going on in this particular discussion as I do find it fascinating.
>
> >> Cheers, Eric- Tekst uit oorspronkelijk bericht niet weergeven -
>
> - Tekst uit oorspronkelijk bericht weergeven -
Mon, 2012-02-20, 16:31
#24
Re: Re: C# async implemented in scala (based on delimited conti
I did not have "Use Project Settings" enabled previously.
I tried enabling "Use Project Settings" and setting
"continuations:enable" in the P field, but that just produces "bad
option: -P:continuations:enable" as well.
This has been my ongoing problem with continuations in Scala - it is
simply too difficult to configure it to work in Eclipse - consequently I
cannot even experiment with the feature.
Should I create a JIRA issue on this?
Cheers, Eric
On 2012-02-20 4:26 AM, Dave wrote:
> Maybe you have Use Project Properties enabled
>
> Then you can fill them in on project level in Project> Properties>
> Scala Compiler
>
> and clean project before running
>
> On 19 feb, 17:03, Eric Kolotyluk wrote:
>> The Eclipse IDE shows
>>
>> bad option: -P:continuations:enable
>>
>> On 2012-02-18 7:04 AM, Dave wrote:
>>
>>
>>
>>> Have you in Eclipse entered continuations:enable in the P textbox?
>>> You can find it in Preferences> Scala> Compiler on the Standard tab
>>> Maybe you have to clean you project too (if you have a false
>>> NoSuchMethod error bugging you).
>>> That is all there is. (No Xplugin path to continuations.jar necessary
>>> on the Advanced tab, someone suggested that in scala-ide bugreport,
>>> but I don't have it and it works too)
>>> Create a scala project
>>> This code works with scala-ide
>>> Main.scala
>>> ==========
>>> import scala.util.continuations._
>>> object Main extends App {
>>> def is123(n:Int):Boolean = {
>>> reset {
>>> shift { k : (Int=>String) =>
>>> (k(n) == "123")
>>> }.toString
>>> }
>>> }
>>> println("the result is " +
>>> reset {
>>> shift { k: (Int=>Int) =>
>>> k(k(k(7)))
>>> } + 1
>>> })
>>> println("123 == 123? result is " + is123(123))
>>> println("567 == 123? result is " + is123(567))
>>> }
>>> Output:
>>> ======
>>> the result is 10
>>> 123 == 123? result is true
>>> 567 == 123? result is false
>>> On 18 feb, 00:23, Eric Kolotyluk wrote:
>>>> I have been trying to follow this discussion, as it really fascinates
>>>> me, and while I get the gist of it, I cannot grok it.
>>>> I still struggle with continuations in Scala
>>>> 1. I have never been able to get them to work in the Eclipse/Scala
>>>> environment. It would be nice if they could 'just work' - but they
>>>> don't. Consequently I cannot even play with them.
>>>> 2. I have not internalized the concepts the way one would internalize
>>>> say recursion or closures.
>>>> I have an interest in continuations particularly in the context of being
>>>> able to write UI code that can only run on a single thread, but has to
>>>> interact with background tasks and asynchronous activities.
>>>> I would appreciate it if someone could take the time explain what is
>>>> going on in this particular discussion as I do find it fascinating.
>>>> Cheers, Eric- Tekst uit oorspronkelijk bericht niet weergeven -
>> - Tekst uit oorspronkelijk bericht weergeven -
Mon, 2012-02-20, 17:21
#25
Re: Re: C# async implemented in scala (based on delimited conti
On Mon, Feb 20, 2012 at 13:29, Eric Kolotyluk wrote:
> I did not have "Use Project Settings" enabled previously.
>
> I tried enabling "Use Project Settings" and setting "continuations:enable"
> in the P field, but that just produces "bad option: -P:continuations:enable"
> as well.
It sounds like you are using Scala 2.8.x... are you?
>
> This has been my ongoing problem with continuations in Scala - it is simply
> too difficult to configure it to work in Eclipse - consequently I cannot
> even experiment with the feature.
>
> Should I create a JIRA issue on this?
>
> Cheers, Eric
>
>
> On 2012-02-20 4:26 AM, Dave wrote:
>>
>> Maybe you have Use Project Properties enabled
>>
>> Then you can fill them in on project level in Project> Properties>
>> Scala Compiler
>>
>> and clean project before running
>>
>> On 19 feb, 17:03, Eric Kolotyluk wrote:
>>>
>>> The Eclipse IDE shows
>>>
>>> bad option: -P:continuations:enable
>>>
>>> On 2012-02-18 7:04 AM, Dave wrote:
>>>
>>>
>>>
>>>> Have you in Eclipse entered continuations:enable in the P textbox?
>>>> You can find it in Preferences> Scala> Compiler on the Standard
>>>> tab
>>>> Maybe you have to clean you project too (if you have a false
>>>> NoSuchMethod error bugging you).
>>>> That is all there is. (No Xplugin path to continuations.jar necessary
>>>> on the Advanced tab, someone suggested that in scala-ide bugreport,
>>>> but I don't have it and it works too)
>>>> Create a scala project
>>>> This code works with scala-ide
>>>> Main.scala
>>>> ==========
>>>> import scala.util.continuations._
>>>> object Main extends App {
>>>> def is123(n:Int):Boolean = {
>>>> reset {
>>>> shift { k : (Int=>String) =>
>>>> (k(n) == "123")
>>>> }.toString
>>>> }
>>>> }
>>>> println("the result is " +
>>>> reset {
>>>> shift { k: (Int=>Int) =>
>>>> k(k(k(7)))
>>>> } + 1
>>>> })
>>>> println("123 == 123? result is " + is123(123))
>>>> println("567 == 123? result is " + is123(567))
>>>> }
>>>> Output:
>>>> ======
>>>> the result is 10
>>>> 123 == 123? result is true
>>>> 567 == 123? result is false
>>>> On 18 feb, 00:23, Eric Kolotyluk wrote:
>>>>>
>>>>> I have been trying to follow this discussion, as it really fascinates
>>>>> me, and while I get the gist of it, I cannot grok it.
>>>>> I still struggle with continuations in Scala
>>>>> 1. I have never been able to get them to work in the Eclipse/Scala
>>>>> environment. It would be nice if they could 'just work' - but they
>>>>> don't. Consequently I cannot even play with them.
>>>>> 2. I have not internalized the concepts the way one would internalize
>>>>> say recursion or closures.
>>>>> I have an interest in continuations particularly in the context of
>>>>> being
>>>>> able to write UI code that can only run on a single thread, but has to
>>>>> interact with background tasks and asynchronous activities.
>>>>> I would appreciate it if someone could take the time explain what is
>>>>> going on in this particular discussion as I do find it fascinating.
>>>>> Cheers, Eric- Tekst uit oorspronkelijk bericht niet weergeven -
>>>
>>> - Tekst uit oorspronkelijk bericht weergeven -
Mon, 2012-02-20, 18:01
#26
Re: Re: C# async implemented in scala (based on delimited conti
As far as I can tell I am using Scala 2.9.0.1 - at least that is all I
have installed - unless Scala on Eclipse is using some embedded Scala.
Cheers, Eric
On 2012-02-20 8:12 AM, Daniel Sobral wrote:
> On Mon, Feb 20, 2012 at 13:29, Eric Kolotyluk wrote:
>> I did not have "Use Project Settings" enabled previously.
>>
>> I tried enabling "Use Project Settings" and setting "continuations:enable"
>> in the P field, but that just produces "bad option: -P:continuations:enable"
>> as well.
> It sounds like you are using Scala 2.8.x... are you?
>
>> This has been my ongoing problem with continuations in Scala - it is simply
>> too difficult to configure it to work in Eclipse - consequently I cannot
>> even experiment with the feature.
>>
>> Should I create a JIRA issue on this?
>>
>> Cheers, Eric
>>
>>
>> On 2012-02-20 4:26 AM, Dave wrote:
>>> Maybe you have Use Project Properties enabled
>>>
>>> Then you can fill them in on project level in Project> Properties>
>>> Scala Compiler
>>>
>>> and clean project before running
>>>
>>> On 19 feb, 17:03, Eric Kolotyluk wrote:
>>>> The Eclipse IDE shows
>>>>
>>>> bad option: -P:continuations:enable
>>>>
>>>> On 2012-02-18 7:04 AM, Dave wrote:
>>>>
>>>>
>>>>
>>>>> Have you in Eclipse entered continuations:enable in the P textbox?
>>>>> You can find it in Preferences> Scala> Compiler on the Standard
>>>>> tab
>>>>> Maybe you have to clean you project too (if you have a false
>>>>> NoSuchMethod error bugging you).
>>>>> That is all there is. (No Xplugin path to continuations.jar necessary
>>>>> on the Advanced tab, someone suggested that in scala-ide bugreport,
>>>>> but I don't have it and it works too)
>>>>> Create a scala project
>>>>> This code works with scala-ide
>>>>> Main.scala
>>>>> ==========
>>>>> import scala.util.continuations._
>>>>> object Main extends App {
>>>>> def is123(n:Int):Boolean = {
>>>>> reset {
>>>>> shift { k : (Int=>String) =>
>>>>> (k(n) == "123")
>>>>> }.toString
>>>>> }
>>>>> }
>>>>> println("the result is " +
>>>>> reset {
>>>>> shift { k: (Int=>Int) =>
>>>>> k(k(k(7)))
>>>>> } + 1
>>>>> })
>>>>> println("123 == 123? result is " + is123(123))
>>>>> println("567 == 123? result is " + is123(567))
>>>>> }
>>>>> Output:
>>>>> ======
>>>>> the result is 10
>>>>> 123 == 123? result is true
>>>>> 567 == 123? result is false
>>>>> On 18 feb, 00:23, Eric Kolotyluk wrote:
>>>>>> I have been trying to follow this discussion, as it really fascinates
>>>>>> me, and while I get the gist of it, I cannot grok it.
>>>>>> I still struggle with continuations in Scala
>>>>>> 1. I have never been able to get them to work in the Eclipse/Scala
>>>>>> environment. It would be nice if they could 'just work' - but they
>>>>>> don't. Consequently I cannot even play with them.
>>>>>> 2. I have not internalized the concepts the way one would internalize
>>>>>> say recursion or closures.
>>>>>> I have an interest in continuations particularly in the context of
>>>>>> being
>>>>>> able to write UI code that can only run on a single thread, but has to
>>>>>> interact with background tasks and asynchronous activities.
>>>>>> I would appreciate it if someone could take the time explain what is
>>>>>> going on in this particular discussion as I do find it fascinating.
>>>>>> Cheers, Eric- Tekst uit oorspronkelijk bericht niet weergeven -
>>>> - Tekst uit oorspronkelijk bericht weergeven -
>
>
Mon, 2012-02-20, 19:31
#27
Re: C# async implemented in scala (based on delimited continuati
And you have set textbox Xplugin on the Advanced tab the path to
continuations.jar
e.g.
C:\scala-2.9.1.final\misc\scala-devel\plugins\continuations.jar
Probably for you it is
C:\scala-2.9.0.1\misc\scala-devel\plugins\continuations.jar
otherwise you can search
You can see what version of Scala your project is using see Scala
Library and then between the square brackets is the version
On 20 feb, 17:47, Eric Kolotyluk wrote:
> As far as I can tell I am using Scala 2.9.0.1 - at least that is all I
> have installed - unless Scala on Eclipse is using some embedded Scala.
>
> Cheers, Eric
>
> On 2012-02-20 8:12 AM, Daniel Sobral wrote:
>
>
>
> > On Mon, Feb 20, 2012 at 13:29, Eric Kolotyluk wrote:
> >> I did not have "Use Project Settings" enabled previously.
>
> >> I tried enabling "Use Project Settings" and setting "continuations:enable"
> >> in the P field, but that just produces "bad option: -P:continuations:enable"
> >> as well.
> > It sounds like you are using Scala 2.8.x... are you?
>
> >> This has been my ongoing problem with continuations in Scala - it is simply
> >> too difficult to configure it to work in Eclipse - consequently I cannot
> >> even experiment with the feature.
>
> >> Should I create a JIRA issue on this?
>
> >> Cheers, Eric
>
> >> On 2012-02-20 4:26 AM, Dave wrote:
> >>> Maybe you have Use Project Properties enabled
>
> >>> Then you can fill them in on project level in Project> Properties>
> >>> Scala Compiler
>
> >>> and clean project before running
>
> >>> On 19 feb, 17:03, Eric Kolotyluk wrote:
> >>>> The Eclipse IDE shows
>
> >>>> bad option: -P:continuations:enable
>
> >>>> On 2012-02-18 7:04 AM, Dave wrote:
>
> >>>>> Have you in Eclipse entered continuations:enable in the P textbox?
> >>>>> You can find it in Preferences> Scala> Compiler on the Standard
> >>>>> tab
> >>>>> Maybe you have to clean you project too (if you have a false
> >>>>> NoSuchMethod error bugging you).
> >>>>> That is all there is. (No Xplugin path to continuations.jar necessary
> >>>>> on the Advanced tab, someone suggested that in scala-ide bugreport,
> >>>>> but I don't have it and it works too)
> >>>>> Create a scala project
> >>>>> This code works with scala-ide
> >>>>> Main.scala
> >>>>> ==========
> >>>>> import scala.util.continuations._
> >>>>> object Main extends App {
> >>>>> def is123(n:Int):Boolean = {
> >>>>> reset {
> >>>>> shift { k : (Int=>String) =>
> >>>>> (k(n) == "123")
> >>>>> }.toString
> >>>>> }
> >>>>> }
> >>>>> println("the result is " +
> >>>>> reset {
> >>>>> shift { k: (Int=>Int) =>
> >>>>> k(k(k(7)))
> >>>>> } + 1
> >>>>> })
> >>>>> println("123 == 123? result is " + is123(123))
> >>>>> println("567 == 123? result is " + is123(567))
> >>>>> }
> >>>>> Output:
> >>>>> ======
> >>>>> the result is 10
> >>>>> 123 == 123? result is true
> >>>>> 567 == 123? result is false
> >>>>> On 18 feb, 00:23, Eric Kolotyluk wrote:
> >>>>>> I have been trying to follow this discussion, as it really fascinates
> >>>>>> me, and while I get the gist of it, I cannot grok it.
> >>>>>> I still struggle with continuations in Scala
> >>>>>> 1. I have never been able to get them to work in the Eclipse/Scala
> >>>>>> environment. It would be nice if they could 'just work' - but they
> >>>>>> don't. Consequently I cannot even play with them.
> >>>>>> 2. I have not internalized the concepts the way one would internalize
> >>>>>> say recursion or closures.
> >>>>>> I have an interest in continuations particularly in the context of
> >>>>>> being
> >>>>>> able to write UI code that can only run on a single thread, but has to
> >>>>>> interact with background tasks and asynchronous activities.
> >>>>>> I would appreciate it if someone could take the time explain what is
> >>>>>> going on in this particular discussion as I do find it fascinating.
> >>>>>> Cheers, Eric- Tekst uit oorspronkelijk bericht niet weergeven -
> >>>> - Tekst uit oorspronkelijk bericht weergeven -- Tekst uit oorspronkelijk bericht niet weergeven -
>
> - Tekst uit oorspronkelijk bericht weergeven -
Mon, 2012-02-20, 23:21
#28
Re: Re: C# async implemented in scala (based on delimited conti
Wha-Hoo - got it to compile and run. Thanks so much :-)
Kinda sucks that the path in the Xplugin cannot have any spaces in the
name. I had to move the plug-in somewhere else. My Scala is installed in
C:\Program Files (Open)\Scala\scala-2.9.0.1
I guess continuations are still consider experimental which is why there
is so much fuss around setting them up in Eclipse.
Cheers, Eric
On 2012-02-20 10:23 AM, Dave wrote:
> And you have set textbox Xplugin on the Advanced tab the path to
> continuations.jar
> e.g.
> C:\scala-2.9.1.final\misc\scala-devel\plugins\continuations.jar
>
>
> Probably for you it is
> C:\scala-2.9.0.1\misc\scala-devel\plugins\continuations.jar
> otherwise you can search
>
> You can see what version of Scala your project is using see Scala
> Library and then between the square brackets is the version
>
> On 20 feb, 17:47, Eric Kolotyluk wrote:
>> As far as I can tell I am using Scala 2.9.0.1 - at least that is all I
>> have installed - unless Scala on Eclipse is using some embedded Scala.
>>
>> Cheers, Eric
>>
>> On 2012-02-20 8:12 AM, Daniel Sobral wrote:
>>
>>
>>
>>> On Mon, Feb 20, 2012 at 13:29, Eric Kolotyluk wrote:
>>>> I did not have "Use Project Settings" enabled previously.
>>>> I tried enabling "Use Project Settings" and setting "continuations:enable"
>>>> in the P field, but that just produces "bad option: -P:continuations:enable"
>>>> as well.
>>> It sounds like you are using Scala 2.8.x... are you?
>>>> This has been my ongoing problem with continuations in Scala - it is simply
>>>> too difficult to configure it to work in Eclipse - consequently I cannot
>>>> even experiment with the feature.
>>>> Should I create a JIRA issue on this?
>>>> Cheers, Eric
>>>> On 2012-02-20 4:26 AM, Dave wrote:
>>>>> Maybe you have Use Project Properties enabled
>>>>> Then you can fill them in on project level in Project> Properties>
>>>>> Scala Compiler
>>>>> and clean project before running
>>>>> On 19 feb, 17:03, Eric Kolotyluk wrote:
>>>>>> The Eclipse IDE shows
>>>>>> bad option: -P:continuations:enable
>>>>>> On 2012-02-18 7:04 AM, Dave wrote:
>>>>>>> Have you in Eclipse entered continuations:enable in the P textbox?
>>>>>>> You can find it in Preferences> Scala> Compiler on the Standard
>>>>>>> tab
>>>>>>> Maybe you have to clean you project too (if you have a false
>>>>>>> NoSuchMethod error bugging you).
>>>>>>> That is all there is. (No Xplugin path to continuations.jar necessary
>>>>>>> on the Advanced tab, someone suggested that in scala-ide bugreport,
>>>>>>> but I don't have it and it works too)
>>>>>>> Create a scala project
>>>>>>> This code works with scala-ide
>>>>>>> Main.scala
>>>>>>> ==========
>>>>>>> import scala.util.continuations._
>>>>>>> object Main extends App {
>>>>>>> def is123(n:Int):Boolean = {
>>>>>>> reset {
>>>>>>> shift { k : (Int=>String) =>
>>>>>>> (k(n) == "123")
>>>>>>> }.toString
>>>>>>> }
>>>>>>> }
>>>>>>> println("the result is " +
>>>>>>> reset {
>>>>>>> shift { k: (Int=>Int) =>
>>>>>>> k(k(k(7)))
>>>>>>> } + 1
>>>>>>> })
>>>>>>> println("123 == 123? result is " + is123(123))
>>>>>>> println("567 == 123? result is " + is123(567))
>>>>>>> }
>>>>>>> Output:
>>>>>>> ======
>>>>>>> the result is 10
>>>>>>> 123 == 123? result is true
>>>>>>> 567 == 123? result is false
>>>>>>> On 18 feb, 00:23, Eric Kolotyluk wrote:
>>>>>>>> I have been trying to follow this discussion, as it really fascinates
>>>>>>>> me, and while I get the gist of it, I cannot grok it.
>>>>>>>> I still struggle with continuations in Scala
>>>>>>>> 1. I have never been able to get them to work in the Eclipse/Scala
>>>>>>>> environment. It would be nice if they could 'just work' - but they
>>>>>>>> don't. Consequently I cannot even play with them.
>>>>>>>> 2. I have not internalized the concepts the way one would internalize
>>>>>>>> say recursion or closures.
>>>>>>>> I have an interest in continuations particularly in the context of
>>>>>>>> being
>>>>>>>> able to write UI code that can only run on a single thread, but has to
>>>>>>>> interact with background tasks and asynchronous activities.
>>>>>>>> I would appreciate it if someone could take the time explain what is
>>>>>>>> going on in this particular discussion as I do find it fascinating.
>>>>>>>> Cheers, Eric- Tekst uit oorspronkelijk bericht niet weergeven -
>>>>>> - Tekst uit oorspronkelijk bericht weergeven -- Tekst uit oorspronkelijk bericht niet weergeven -
>> - Tekst uit oorspronkelijk bericht weergeven -
Sweet! Would this version of async
def async[A](body: => A @suspendable) = {
val p = promise[A]
reset { p success body }
p
}
work for the extended case you mention?
val a: Future[Int] = async[Int] {
val com = await { dlWebSite("http://www.google.com") }
com.length
}
a onSuccess { case r => .... }
- Tiark
On Feb 16, 2012, at 1:28 AM, Daniel wrote:
> Hi all
>
> In order to get a better understanding about delimited continuations I
> tried to implement something akin to C# async [1]. Since I think this
> has the potential to be cool, I share it with you. I would appreciate
> any hints and comments.
>
> As a substitute for C#s Tasks I went with akka 2.0 Futures [2] since
> those will eventually be integrated into the main library [3] afaik.
> I have the following:
>
>
> == Example ==
>
> context(GUI) { implicit ec =>
> async {
> m("1")
>
> val contentCom = await { dlWebSite("http://www.google.com") }
> m("2 " + contentCom)
>
> val contentCh = await { dlWebSite("http://www.google.ch") }
> m("3 " + contentCh)
>
> val contentDe = await { dlWebSite("http://www.google.de") }
> m("4 " + contentDe)
> }
> }
>
> // Returns a Future which will eventually hold the downloaded html.
> // The download itself is scheduled on a thread pool.
> def dlWebSite(url: String): Future[String] = Future {
> m("downloading: " + url)
> Source.fromURL(new URL(url))
> (Codec.ISO8859).getLines.mkString.take(20)
> }(ThreadPool)
>
> // Prints msg prefixed with the name of the current thread
> def m(msg: String) = println(Thread.currentThread().getName() + " '" +
> msg + "'")
>
>
> == Output ==
>
> UI '1'
> pool-1-thread-1 'downloading: http://www.google.com'
> UI '2 pool-1-thread-3 'downloading: http://www.google.ch'
> UI '3 pool-1-thread-5 'downloading: http://www.google.de'
> UI '4
> As you can see, the hard work is executed on a thread pool but the
> results are again on the UI thread. No blocking behind the scenes.
>
>
> == Implementation ==
>
> // The async method is nothing more than a nice name for
> // scala.util.continuations.reset
> def async[B](block: => Unit@suspendable): Unit = reset[Unit,Unit]
> { block }
>
> // The await method takes a block which returns a Future[A] and
> // pretends to return an A to the caller. Without continuations, this
> would be
> // only possible by waiting (blocking) on the future until the result
> is ready.
> def await[A](block: => Future[A])(implicit ec: ExecutionContext =
> ThreadPool): A@suspendable = shift { cont: (A => Unit) =>
> block onSuccess { case r => ec.execute{ cont(r) } }
> }
>
> // The context method is used to put an ExecutionContext into scope
> // which runs the given block. It primarily exists to give nice
> // looking examples.
> def context[T](ec: ExecutionContext)(block: ExecutionContext => T)
> { ec.execute{ block(ec) } }
>
> // Dummy placeholder to simulate the Swing event dispatching thread
> val GUI =
> ExecutionContexts.fromExecutor(Executors.newSingleThreadExecutor(
> new ThreadFactory{ def newThread(r: Runnable): Thread = new
> Thread(r,"UI")}))
>
> // Thread pool for the heavy background work
> val ThreadPool = ExecutionContexts.fromExecutorService(
>
> Executors.newFixedThreadPool(10))
>
> // Runnables without the noise
> implicit def toRunnable[T](f: => T ): Runnable = new Runnable { def
> run() = f }
>
>
> == The Problem ==
>
> I would like the async block to return a Future of its syntactic
> return value:
>
> val a: Future[Int] = async[Int] {
> m("1")
> val com = await[String,Int,NotLast] {
> dlWebSite("http://www.google.com")
> }
> m("2 " + com)
>
> val ch = await[String,Int,NotLast] {
> dlWebSite("http://www.google.ch")
> }
> m("3 " + ch)
>
> val de = await[String,Int,Last] {
> dlWebSite("http://www.google.de")
> }
> m("4 " + de)
>
> de.length() // this should be returned as a Future[Int]
> }
> a onSuccess { case r => m("res" + r) }
>
>
> == Output ==
>
> UI '1'
> pool-1-thread-1 'downloading: http://www.google.com'
> UI '2 pool-1-thread-3 'downloading: http://www.google.ch'
> UI '3 pool-1-thread-5 'downloading: http://www.google.de'
> UI '4 UI 'res20'
>
> The good part is that it works. The problem is, that now all
> those hairy type declarations are required. I could life with
> await[String,Int] {...} but my solution requires a further type
> parameter to distinguish whether it is the last await in a reset
> block or not. The last await turns the Int into a Future[Int]
> and all awaits above that last one need to reflect this in their
> type. Here is the code:
>
> // Better name for reset. Takes a block with a syntactic return type
> // of B and returns a Future[B]
> def async[B](block: => B@cpsParam[B,Future[B]]): Future[B] =
> reset[B,Future[B]] { block }
>
> // The D[_] type parameter is required in @cpsParam.
> // Depending on the given type the matching implicit is searched.
> def await[A,B,D[_]] (block: => Future[A])
> (implicit ec: ExecutionContext = ThreadPool,
> f: (=> Future[A]) => ExecutionContext => A@cpsParam[D[B],Future[B]]
> ):A@cpsParam[D[B],Future[B]] = f(block)(ec)
>
>
> type Last[X] = X
>
> // The last await needs a continuation form A => Last[B] which is from
> A => B
> implicit def last[A,B]: (=> Future[A]) => ExecutionContext =>
> A@cpsParam[Last[B],Future[B]] = {
> block => ec => shift[A,Last[B],Future[B]] { cont: (A => Last[B]) =>
> val p = Promise[B]()(ec)
> block onSuccess { case a => ec.execute{ p.success(cont(a)) } }
> p
> }
> }
>
> type NotLast[X] = Future[X]
>
> // All other awaits need a continuation from A => NotLast[B]
> // which is from A => Future[B]
> implicit def notLast[A,B]: (=> Future[A]) => ExecutionContext =>
> A@cpsParam[NotLast[B],Future[B]] = {
> block => ec => shift[A,NotLast[B],Future[B]] { cont: (A =>
> NotLast[B]) =>
> val p = Promise[B]()(ec)
> block onSuccess { case a =>
> ec.execute{ p.completeWith(cont(a)) } }
> p
> }
> }
>
> This was the best solution I was able to come up with. Of course I
> could offer two different await methods which would be a simple
> solution if they had different names. But that is not an option. BTW I
> am fully aware that the presented code has at most toy quality (
> handles only onSuccess, etc.). Anyway, thanks for reading that far. If
> you want to learn about scala's continuations I recommend reading this
> blog post [4] by Jim McBeath.
>
> Thanks Daniel
>
>
> [1] http://msdn.microsoft.com/en-us/vstudio/gg316360
> [2] http://akka.io/docs/akka/2.0-RC1/scala/futures.html
> [3] http://docs.scala-lang.org/sips/pending/futures-promises.html
> [4] http://jim-mcbeath.blogspot.com/2010/08/delimited-continuations.html