2

Scala 2.10.2. Running

import util.continuations._
import concurrent.ops._

object Main {
    def main(args: Array[String]) {
        reset {
            try {
                shift { cont: (Unit => Unit) => {
                    spawn {
                        throw new Exception("blah")
                        cont()
                    }
                }}
                println("after shift")
            } catch {
                case e: Exception => println(e)
            }
            println("reset end")
        }
    }
}

Gives

Cont.scala:16: error: type mismatch;
 found   : Unit
 required: Unit @scala.util.continuations.cpsParam[Unit,Unit]
                case e: Exception => println(e)
                                            ^
one error found

If I remove the try/catch block everything's fine. I'm still trying to figure out how continuations work in Scala, but this one totally eludes me.

Yuri Geinish
  • 16,744
  • 6
  • 38
  • 40

2 Answers2

1

Just stating the obvious - It is a Scala type inference meets cps-annotation problem. The catch block do not contain any cps annotated expression. In this case the catch-block is expected to be of the same type as the try-block:

Unit @cps[Unit] // same as Unit @cpsParam[Unit,Unit]

To my experience, the type-inference and the CPS-transformation in Scala does not always work as expected and things that work in one version of Scala do not work in another version.

There exists workarounds such as the try_protector mentioned in Scala Continuations - Why can't my shifted call be inside a try-catch block?

Not sure if it helps in your case (i.e. Scala version 2.10.2).

Community
  • 1
  • 1
Jockbert
  • 92
  • 6
0

Do you intend the try/catch statement to catch Exception("blah")?

Even if it compiled, spawn which is deprecated would happen on another thread before the flow gets to running the continuation.

Without the try/catch you have something like this:

println("in main " + Thread.currentThread())
reset {
  shift { cont: (Unit => Unit) =>
    {
      spawn {
        println("in spawned " + Thread.currentThread())
        cont()
      }
    }
  }
  println("after shift " + Thread.currentThread())
  println("reset end")
}

}

The cont function is the reified portion of code which corresponds to this function:

val cont = () => {
  println("after shift " + Thread.currentThread())
  println("reset end")
}

So when you do spawn { cont() }, you just run the two println in a new separate thread. Running the program, I get:

in main Thread[main,5,main]
in spawned Thread[Thread-1,5,main]
after shift Thread[Thread-1,5,main]
reset end

That shows that the continuation ran on a separate thread. Now if you insert a throw new Exception() before cont(), then all you get is an exception thrown on the spawned thread (where apparently the exception would be swallowed).

Would running the continuation inside a try/catch and having an exception thrown after the shift be more what you are trying to do?

reset {
  shift { cont: (Unit => Unit) =>
    spawn {
      println("in spawned " + Thread.currentThread())
      try { cont() }
      catch { case e: Exception => println(e) }
    }
  }
  println("after shift " + Thread.currentThread())
  throw new Exception("blah")
  println("reset end")
}

}

This prints:

in main Thread[main,5,main]
in spawned Thread[Thread-1,5,main]
after shift Thread[Thread-1,5,main]
java.lang.Exception: blah
huynhjl
  • 41,520
  • 14
  • 105
  • 158