src/Pure/Concurrent/future.scala
author wenzelm
Mon, 04 Jan 2010 18:54:22 +0100
changeset 34240 3274571e45c1
parent 34217 67e1ac2d3b2c
child 34262 a6d2d9c07e46
permissions -rw-r--r--
added Future.promise -- essentially a single-assignment variable with signalling, using the Future interface;

/*  Title:      Pure/Concurrent/future.scala
    Author:     Makarius

Future values.

Notable differences to scala.actors.Future (as of Scala 2.7.7):

  * We capture/release exceptions as in the ML variant.

  * Future.join works for *any* actor, not just the one of the
    original fork.
*/

package isabelle


import scala.actors.Actor._


object Future
{
  def value[A](x: A): Future[A] = new Finished_Future(x)
  def fork[A](body: => A): Future[A] = new Pending_Future(body)
  def promise[A]: Promise[A] = new Promise_Future
}

abstract class Future[A]
{
  def peek: Option[Exn.Result[A]]
  def is_finished: Boolean = peek.isDefined
  def join: A
  def map[B](f: A => B): Future[B] = Future.fork { f(join) }

  override def toString =
    peek match {
      case None => "<future>"
      case Some(Exn.Exn(_)) => "<failed>"
      case Some(Exn.Res(x)) => x.toString
    }
}

abstract class Promise[A] extends Future[A]
{
  def fulfill(x: A): Unit
}

private class Finished_Future[A](x: A) extends Future[A]
{
  val peek: Option[Exn.Result[A]] = Some(Exn.Res(x))
  val join: A = x
}

private class Pending_Future[A](body: => A) extends Future[A]
{
  @volatile private var result: Option[Exn.Result[A]] = None

  private val evaluator = actor {
    result = Some(Exn.capture(body))
    loop { react { case _ => reply(result.get) } }
  }

  def peek: Option[Exn.Result[A]] = result

  def join: A =
    Exn.release {
      peek match {
        case Some(res) => res
        case None => (evaluator !? ()).asInstanceOf[Exn.Result[A]]
      }
    }
}

private class Promise_Future[A] extends Promise[A]
{
  @volatile private var result: Option[A] = None

  private case object Read
  private case class Write(x: A)

  private val receiver = actor {
    loop {
      react {
        case Read if result.isDefined => reply(result.get)
        case Write(x) =>
          if (result.isDefined) reply(false)
          else { result = Some(x); reply(true) }
      }
    }
  }

  def peek: Option[Exn.Result[A]] = result.map(Exn.Res(_))

  def join: A =
    result match {
      case Some(res) => res
      case None => (receiver !? Read).asInstanceOf[A]
    }

  def fulfill(x: A) {
    receiver !? Write(x) match {
      case false => error("Duplicate fulfillment of promise")
      case _ =>
    }
  }
}