matanox
matanox

Reputation: 13686

Getting the result of a Scala promise without a future

Is there a way to directly get the value out of a successful promise? Is it really necessary to connect a future to the promise, for that?

scala> import scala.concurrent._
import scala.concurrent._

scala> val result = Promise[Int]
result: scala.concurrent.Promise[Int] = scala.concurrent.impl.Promise$DefaultPromise@2b5fa85f

scala> result success 3
res0: result.type = scala.concurrent.impl.Promise$DefaultPromise@2b5fa85f

scala> result
res1: scala.concurrent.Promise[Int] = scala.concurrent.impl.Promise$DefaultPromise@2b5fa85f

scala> result.isCompleted
res4: Boolean = true

scala> result.value
<console>:12: error: value value is not a member of scala.concurrent.Promise[Int]
              result.value
                     ^

scala> result.future.value.get.get
res6: Int = 3

I am considering using a promise for thread-safe "assign once" semantics. The promise object looks lean enough in the scala.concurrent source, and as far as I understand it is thread safe. I'd rather however, avoid adding another object (a future). I could not find a getter for the success value of a promise.

Upvotes: 3

Views: 2045

Answers (2)

Gabriele Petronella
Gabriele Petronella

Reputation: 108101

tl; dr

p.future == p

so don't worry about the extra allocation.


discussion

Promise and Future are complimentary. The former represents the write (once) side of the computation, while the latter is the read side.

So, in order to read a value from a Promise you will always need to do it via a Future.

On the other hand, it's worth noting that despite the abstract design, the implementation is quite efficient and Promise and Future are not separate entities. Here's the implementation of the future of Promise

private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with scala.concurrent.Future[T] {
  def future: this.type = this
}

So, you can see that p.future is actuall the same as p, and it simply gets a different semantic.

Bottom line, you can access future from promise and you won't be paying any additional cost in terms of instance allocations.

Also, you can make the syntax nicer if you wish

scala> implicit class DirectAccessPromise[A](val p: Promise[A]) extends AnyVal {
     |   def get = p.future.value.get.get
     | }
defined class DirectAccessPromise

scala> val p = Promise.successful(42)
res0: scala.concurrent.Promise[Int] = scala.concurrent.impl.Promise$KeptPromise@5e8c92f4

scala> p.get
res1: Int = 42

Note that since the wrapper is a value class, you won't be paying any extra-instantiation price

Upvotes: 9

dwickern
dwickern

Reputation: 3519

The DefaultPromise returns itself as the future, so you aren't making an extra allocation. Even if you were, the cost of the thread safety is likely much greater.

Upvotes: 4

Related Questions