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.
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.
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.
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With