Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Future[Option[Boolean]] in a for comprehension.. Simple right?

Suppose I have:

val res:Future[Option[Boolean]] = Future(Some(true))

and I can do:

res.map(opt => opt.map(r => print(!r)))

I guess the for comprehension for this would be:

for {
   opt <- res
   r <- opt
} yield (print(!r))

but this does not work! I get an error ie:

error: type mismatch;
found   : Option[Unit]
required: scala.concurrent.Future[?]
r <- opt

How do I use a Future[Option[Boolean]] in a for comprehension to extract or convert the Boolean?

Note: this is a simplification of the problem I have at the moment with many Future[Option[Boolean]] variables that I would like to use together in a for comprehension.

like image 878
Simon C Avatar asked Jan 03 '14 01:01

Simon C


People also ask

How do you pass a future option to buydonuts?

Chaining Future Option using for comprehension Since donutStock () method returns a Future Option of type Int, someStock is in fact an Option of type Int. In order to pass-through someStock to the buyDonuts () method as input parameter, we are making use of the getOrElse () method from Option.

Which method returns a future option of type int?

Let's make use of our donutStock () method which returns a Future Option of type Int. println ("Step 1: Define a method which returns a Future Option") import scala. concurrent. Future import scala. concurrent.

What is the difference between list comprehensions and set comprehensions?

Set comprehensions are pretty similar to list comprehensions. The only difference between them is that set comprehensions use curly brackets { }. Let’s look at the following example to understand set comprehensions. Example #1 : Suppose we want to create an output set which contains only the even numbers that are present in the input list.

How do you return a future from a method?

Define a method which returns a Future In the Method with future return type section, we showed how to create an asynchronous method by adding the Future return type. Let's reuse the method donutStock () which returns a Future of type Int to represent the donut stock for a particular donut.


1 Answers

A for-comprehension really makes this look like it should all work, doesn't it? But let's think about what you're asking for.

First, note that for un-nests:

for {xs <- List(List(5)); x <- xs} yield x

produces

List(5)

Now, without even getting into the type signatures or desugaring, we can think about replacing List with some arbitrary type T, and we'll call the contained type A:

for { xs <- T(T(a: A)); x <- xs } yield x

and we should get a

T[A]

back (presumably the one we put in, but the types don't actually promise us that).

Okay, but what about

for { xs <- T(U(a: A)); x <- xs } yield x

? This is strictly more general than the case where the two things have the same nesting. Well, if T and U both have a common supertype S, then we can just view the whole thing as S(S(a: A)), so we'll at least get an S back. But what about in the general case?

The bottom line is that it depends. For example, let's consider the case where T=Future, U=Option. We have the following possibilities:

Success(Some(a))
Success(None)
Failure(t: Throwable)

Now, can we come up with any coherent policy for unwrapping? If we unwrap into a Future, then what A do you use for the Success(None) case? You don't have one available to return. Likewise, if you try to vanquish the outer Future, how do you know, without explicitly stating it somehow to the compiler, that Failure should be mapped to None (if indeed it should--maybe it should go to a default!).

So the bottom line is that you just can't do this correctly in general without specifying what is supposed to happen for every pair T[U[_]]. (I encourage the interested reader to peruse tutorials on monads and monad transformers.)

There is a way out, though: if you can explicitly turn your U into a T, or your T into your U, you can take advantage of the unwrapping capability. It's pretty easy to turn an Option into a Future , so the easiest solution is

for { opt <- res; r <- Future(opt.get) } yield r

(where just let the exception get thrown on none.get). Alternatively, you can turn the Future into an Option with the slightly ugly

for { opt <- res.value.flatMap(_.toOption); r <- opt } yield r
like image 117
Rex Kerr Avatar answered Oct 16 '22 07:10

Rex Kerr