Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala Future with filter in for comprehension

Tags:

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 
like image 745
Magnus Avatar asked Jul 25 '13 22:07

Magnus


2 Answers

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" 
like image 158
pkinsky Avatar answered Sep 30 '22 09:09

pkinsky


In your for-comprehension, you are filtering by i == 2. Because the value of f1 is not two, it will not yield a Success but instead a Failure. The predicate of the filter is not satisfied, as your errror message tells you. However, f2.recover returns a new Future. The value of f2 is not manipulated. It still stores the Failure. That is the reason you get the error message when you call f2.value.

The only alternative I can think of would be using an else in your for-comprehension as shown here.

val f2 = for ( i <- f1) yield {   if (i == 2) "Test1"   else "Test2" } f2.value 

This will return Some(Success(Test2)) as your f3.value does.

like image 28
tgr Avatar answered Sep 30 '22 10:09

tgr