Why is scala Await.result timing out in repl when passed the same future twice?
concurrency, scala
Solution
The reason you don't want to start threads from class initializers is that cycles in classloading will block. A Scala object is just an instance created in a static block. The closure's reference to y is a cycle. In 2.11, use -Yrepl-class-based to help it work.
Lets examine the stack trace for the hang when the closure class needs `X.z`:
apm@mara:~$ goof
Welcome to Scala version 2.11.0-RC3 (OpenJDK 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import scala.concurrent._
import scala.concurrent._
scala> import duration._
import duration._
scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global
scala> object X { val y = Future { 9 } ; val z = Future { 7 } ; val r = Await.result(for (a <- y; b <- z) yield (a+b), 5.seconds) }
defined object X
scala> X.r
java.lang.NoClassDefFoundError: Could not initialize class $line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$X$
at $line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$X$$anonfun$3.apply(<console>:14)
at $line15.$read$$iw$$iw$$iw$$iw$$iw$$iw$X$$anonfun$3.apply(<console>:14)
at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:251)
at scala.concurrent.Future$$anonfun$flatMap$1.apply(Future.scala:249)
at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:32)
at scala.concurrent.impl.ExecutionContextImpl$AdaptedForkJoinTask.exec(ExecutionContextImpl.scala:121)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
java.util.concurrent.TimeoutException: Futures timed out after [5 seconds]
at scala.concurrent.impl.Promise$DefaultPromise.ready(Promise.scala:219)
at scala.concurrent.impl.Promise$DefaultPromise.result(Promise.scala:223)
at scala.concurrent.Await$$anonfun$result$1.apply(package.scala:111)
at scala.concurrent.BlockContext$DefaultBlockContext$.blockOn(BlockContext.scala:53)
at scala.concurrent.Await$.result(package.scala:111)
... 34 elided
And just to show it working:
apm@mara:~$ goof -Yrepl-class-based
Welcome to Scala version 2.11.0-RC3 (OpenJDK 64-Bit Server VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import scala.concurrent._
import scala.concurrent._
scala> import duration._
import duration._
scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global
scala> object X { val y = Future { 9 } ; val z = Future { 7 } ; val r = Await.result(for (a <- y; b <- z) yield (a+b), 5.seconds) }
defined object X
scala> X.r
res0: Int = 16
Problem
I found this a bit confusing. I thought futures in scala are inmutable containers that once set, always return the same value. So I have a future: ``` val y = future {Thread.sleep(1000); 1}; ``` Now when i immediately (before the future resolves) pass it to `Await.result` block twice: ``` Await.result(for (r1 <- y; r2 <- y) yield (r1, r2), 60 seconds) ``` I get a `TimetoutException`. However if i do it once the future is resolved, everything works fine and returns `(1,1)` as expected. What is the reason of this behavior? Edit: I'm using implicit `ExecutionContext.Implicits.global` and `scala.concurrent` @ scala 2.10.3 Edit2: If I create another future instance doing the same thing and do Await.result on them both it doesn't block.