Scala Future with filter in for comprehension

Magnus picture Magnus · Jul 26, 2013 · Viewed 19.8k times · Source

In the example below I get the exception java.util.NoSuchElementException: Future.filter predicate is not satisfied

I want to have the result Future( Test2 ) when the check if( i == 2 ) fails. How do I handle filter/if within a for comprehension that deals with composing futures?

Below is a simplified example that works in the Scala REPL.

Code:

import scala.concurrent.Future
import scala.util.{ Try, Success, Failure }
import scala.concurrent.ExecutionContext.Implicits.global

val f1 = Future( 1 )
val f2 = for {
  i <- f1
  if( i == 2 )
} yield "Test1"
f2.recover{ case _ => "Test2" }
f2.value

Answer

pkinsky picture pkinsky · Mar 9, 2014

This is a more idiomatic solution, in my opinion. This predicate function creates either a Future[Unit] or a failed future containing your exception. For your example, this would result in either a Success("Test1") or a Failure(Exception("Test2")). This is slightly different from "Test1" and "Test2", but I find this syntax to be more useful.

def predicate(condition: Boolean)(fail: Exception): Future[Unit] = 
    if (condition) Future( () ) else Future.failed(fail)

You use it like this:

val f2 = for {
  i <- f1
  _ <- predicate( i == 2 )(new Exception("Test2"))
  j <- f3  // f3 will only run if the predicate is true
} yield "Test1"