简体   繁体   中英

understanding why future result with for comprehension yields Future[Nothing]

Trying to understand why the following expression yields Future[Nothing] and not Future[List[Int]]

def foo(): Future[List[Int]] = Future(List(1,2,3,3,3,4,4,4))
def bar(): Future[Nothing] =for {
    fooList <- foo()
    f <- fooList.distinct
} yield f

of course, this is simplified example, and I can return the fooList directly. But I am trying to understand the reason of getting Future[Nothing] and not Future[List[Int]]

I get a compiler error for your code, which is expected since fooList.distinct should have been a Future for the extractor <- to work on it.

scala> def foo() = Future(List(1,2,2,3))
foo: ()scala.concurrent.Future[List[Int]]


scala> for(fooList <- foo(); f <- fooList.distinct) yield f
<console>:17: error: type mismatch;
 found   : List[Int]
 required: scala.concurrent.Future[?]
              for(fooList <- foo(); f <- fooList.distinct) yield f
                                      ^

This code compiles:

scala> for(fooList <- foo(); f = fooList.distinct) yield f
res4: scala.concurrent.Future[List[Int]] = scala.concurrent.impl.Promise$DefaultPromise@1e387e13

And this code also (wrapping the call to distinct into a Future):

scala> for(fooList <- foo(); f <- Future(fooList.distinct)) yield f
res5: scala.concurrent.Future[List[Int]] = scala.concurrent.impl.Promise$DefaultPromise@623d211
res4: scala.concurrent.Future[List[Int]] = scala.concurrent.impl.Promise$DefaultPromise@1e387e13

Scala's for-comprehension are just syntactic sugar for methods flatMap , map and filter . A code

for {
  x1 <- e1
  x2 =  e2
  x3 <- e3 if e4
  x4 <- e5
} yield e6

translates into (or something equivalent to)

e1.flatMap(x1 =>
e2.map(x2 =>
e3.filter(x3 => e4).flatMap(x3 =>
e5.map(x4 => e6)

The for-comprehension in your example becomes

foo().flatMap(fooList => fooList.distinct.map(f => f))

which is equivalent to

foo().flatMap(fooList => fooList.distinct)

because map(id) = id by definition of what a Functor is. The method foo().flatMap takes an argument of type List[Int] ⇒ Future[S] . But the function fooList => fooList.distinct is of type List[Int] => List[Int] . The compiler checks if the provided type is a subtype of the expected one. In your case the check falls to: is List[Int] a subtype of Future[S] for some type S . I'm not sure why the exepected type S is Nothing but it may be related to Future being covariant (as any Functor should).

Given a future of type Future[T] , map and flatMap both produce a Future[S] but the difference is:

  • map takes arguments of type T => S . Syntax x = ... .
  • flatMap takes arguments of type T => Future[S] . Syntax x <- ... .

The method you want is then map which gives

for (fooList <- foo())
yield fooList.distinct

or

foo().map(fooList => fooList.distinct)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM