The following works with Scala 2.10.0-M6, but in 2.9.2 you can probably achieve something similar using :wrap
in REPL power mode.
Assume that the REPL is started from sbt via sbt console
—without loss of generality (you may otherwise just put the ReplUtil
class on scala's class path). Assume the following class is on the class path, e.g. its source is at src/main/scala/ReplUtil.scala
:
import java.util.concurrent.{Executors, ExecutorService, TimeoutException, TimeUnit}
import concurrent._
object ReplUtil {
@volatile private var exec: ExecutorService = _
@volatile private var threads = Set.empty[ Thread ]
private def freshPool() { exec = Executors.newCachedThreadPool() }
freshPool()
private implicit def context = ExecutionContext.fromExecutorService( exec )
def panic() {
(new Thread {
override def run() {
try {
exec.shutdownNow()
exec.awaitTermination( 1, TimeUnit.SECONDS )
} finally {
val th = threads
threads = Set.empty
th.foreach( _.stop )
freshPool()
}
}
}).start()
}
def spawn[T](t: => T) = {
var futPrint = false
val fut = future {
val th = Thread.currentThread()
threads += th
val res = try { t } finally { threads -= th }
if( futPrint ) println( "<calculation done>\n" + res )
t
}
try {
Await.result( fut, util.Duration( 4, TimeUnit.SECONDS )).toString
} catch {
case e: TimeoutException =>
futPrint = true
"<ongoing calculation>"
}
}
}
Then the following will activate the semi-asynchronous REPL:
$ sbt console
...
Welcome to Scala version 2.10.0-M6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_33).
...
scala> import ReplUtil.panic
import ReplUtil.panic
scala> :power
** Power User mode enabled - BEEP WHIR GYVE **
...
scala> power.intp.setExecutionWrapper("ReplUtil.spawn")
scala> 2+2
res1: Int = 4
scala> Thread.sleep(6000); 33
<ongoing calculation>
scala> <calculation done>
res2: Int = 33
scala> while(true) { Thread.sleep(2000); println( "Zzz" )}
Zzz
Zzz
<ongoing calculation>
scala> panic
scala> [error] (pool-5-thread-1) java.lang.ExceptionInInitializerError
java.lang.ExceptionInInitializerError
...
Caused by: java.lang.InterruptedException: sleep interrupted
...