Failing a Future based on a successful result

11,220

You can do this with less effort with map:

val f = Future{ Result(false) } map {
  case Result(false) => throw new Exception("The call failed!!")
  case x => x
}

but you still need to explicitly mention that you're passing the identity through.

Note that that you should not use andThen in such cases. andThen is for side effects, not for changing the result (unlike the Function1 method of the same name).

Share:
11,220
cmbaxter
Author by

cmbaxter

Long time Java programmer who converted to Scala a few years back. I like building high performance systems built on top of Akka using other libraries like Unfiltered, Slick, Dispatch and Netty. If you like my Akka answers on Stackoverflow then you'll love my book, Mastering Akka. Pick yourself up a copy on pre-sale today. Links below: https://www.packtpub.com/application-development/mastering-akka https://www.amazon.com/Mastering-Akka-Christian-Baxter-ebook/dp/B01GOJCXPU/ref=sr_1_1?ie=UTF8&qid=1465469018&sr=8-1&keywords=Mastering+Akka Linked In http://www.linkedin.com/pub/chris-baxter/3/429/5ab/

Updated on July 10, 2022

Comments

  • cmbaxter
    cmbaxter almost 2 years

    I have a scenario in my code where I need to make a Future fail based on a successful result that contains a certain value. I can make this work just fine via flatMap, but I want to know if there is a cleaner way to make this work. First, a very simplified example:

    import concurrent._
    
    case class Result(successful:Boolean)
    object FutureTest {
      def main(args: Array[String]) {
        import ExecutionContext.Implicits._
    
        val f = Future{Result(false)}.flatMap{ result =>
          result match{
            case Result(false) => Promise.failed(new Exception("The call failed!!")).future
            case _ => Promise.successful(result).future
          }
        }
    
        f onFailure{
          case x => println(x.getMessage())
        }
      }
    }
    

    So in my example here, I want the Future to be failed if the Result returned has a value of false for its success indicator. As I mentioned, I can make this work okay with flatMap, but the line of code I would like to eliminate is:

    case _ => Promise.successful(result).future
    

    This statement seems unnecessary. The behavior that I would like is to be able to define the condition and if it evaluates to true, allow me to return a different Future as I am doing, but if it's not true, just leave things as they are (sort of like PartialFunction semantics. Is there a way to do this that I'm just not seeing? I've looked at collect and transform and those don't seem to be the right fit either.

    Edit

    After getting the map suggestion from @Rex Kerr and @senia, I created a PimpedFuture and an implicit conversion to pretty up the code a bit like so:

    class PimpedFuture[T](f:Future[T])(implicit ex:ExecutionContext){
      def failWhen(pf:PartialFunction[T,Throwable]):Future[T] = {
        f map{
          case x if (pf.isDefinedAt(x)) => throw pf(x)
          case x => x
        }
      }
    }
    

    The implicit

      implicit def futToPimpedFut[T](fut:Future[T])(implicit ec:ExecutionContext):PimpedFuture[T] = new PimpedFuture(fut)
    

    And the new handling code:

    val f = Future{ Result(false) } failWhen {
      case Result(false) => new Exception("The call failed!!")
    }
    

    I think this is a little cleaner while still utilizing the suggestion to use map.