Reputation: 1487
I'm pretty new to Scala, please bear with me. I have a bunch of futures wrapped in a large array. The futures have done their hard work looking through a few TBs of data, and at the end of my app I want to wrap up all the results of said futures so I can present them nicely.
The collection of futures I have is of the following type:
Array[Future[List(String, String, String)]]
Everything I've read so far about the for-comprehension show that
val test: Seq[Seq[List[String]]] = Seq(Seq(List("Hello", "World"), List("What's", "Up")))
val results = for {
test1 <- test
test2 <- test1
test3 <- test2
} yield test3
Results in
results: Seq[String] = List(Hello, World, What's, Up)
By that same logic, my intention was to do it like so, since I recently discovered that Option, Try, Failure and Success can be treated as collections:
val futures = { ... } // Logic that collects my Futures
// futures is now Array[Future[List(String, String, String)]]
val results = for {
// futureSeq as Seq[List(String, String, String]
futureSeq <- Future.sequence(futures.toSeq)
// resultSet as List(String, String, String)
resultSet <- futureSeq
} yield resultset
But this doesn't to work. I seem to be receiving the following compilation errors:
Error:(78, 15) type mismatch;
found : Seq[List(String, String, String)]
required: scala.concurrent.Future[?]resultSet <- futureSeq ^
The part with the required: scala.concurrent.Future[?] is throwing me off completely. I do not understand at all why a Future would be required there.
I have checked the types of all my objects through the REPL, by debugging, and by using IntelliJ's type inspection. They seem to confirm that I'm not just confused about my types.
And before anyone mentions, yes, I am aware that the for-comprehension is syntactic sugar for a bunch of maps, flatMaps and withFilters.
Upvotes: 4
Views: 5017
Reputation: 139058
The details of how the for
-comprehension desugars to calls to flatMap
and map
are important here. This code:
for {
futureSeq <- Future.sequence(futures.toSeq)
resultSet <- futureSeq
} yield resultset
Becomes something more or less like this:
Future.sequence(futures.toSeq).flatMap(futureSeq => futureSeq)
The flatMap
on Future
expects a function that returns a Future
, but you've given it one that returns an Seq[List[(String, String, String)]]
.
In general you can't mix types in for
-comprehensions (Option
in a sequence comprehension is a kind of exception that's supported by an implicit conversion). If you have a <-
arrow coming out of a future, all of the rest of your <-
arrows need to come out of futures.
You probably want something like this:
val results: Future[Seq[(String, String, String)]] =
Future.sequence(futures.toSeq).map(_.flatten)
You could then use something like this:
import scala.concurrent.Await
import scala.concurrent.duration._
Await.result(results.map(_.map(doSomethingWithResult)), 2.seconds)
To synchronously present the results (blocking until its done).
Upvotes: 3