Search code examples
scalaclosuresanonymous-functionfunction-parameter

Success and failure function parameters Scala pattern


Is there an alternative pattern for having success and failure closures in Scala?

There's nothing wrong with this convention that's similar to what node.js libraries normally do, but I'm just wondering if there's another way to do this in Scala.

for example:

def performAsyncAction(n: BigInt,
                success: (BigInt) => Unit,
                failure: FunctionTypes.Failure): Unit = {

Then the call to the function

performAsyncAction(10,
         {(x: BigInt) => 
              /* Code... */
         }, 
         {(t: Throwable) => 
              e.printStackTrace()
         })

Thanks


Solution

  • It sounds like you want a Future. See the AKKA implementation here.

    A Future is a functional construct that lets you specify a block of code to be executed asynchronously and then you can grab the result once it's completed:

    import akka.actor.ActorSystem
    import akka.dispatch.Await
    import akka.dispatch.Future
    import akka.util.duration._
    
    implicit val system = ActorSystem("FutureSystem")
    
    val future = Future {
      1 + 1
    }
    val result = Await.result(future, 1 second)
    println(result) //  prints "2"
    

    You can specify on-failure behavior with the onFailure method (there's also onComplete and onSuccess):

    val future = Future {
      throw new RuntimeException("error")
    }.onFailure {
      case e: RuntimeException => println("Oops!  We failed with " + e)
    }
    //  will print "Oops!  We failed with java.lang.RuntimeException: error"
    

    But the best part is that Futures are Monads, so you can create pipelines of asynchronous actions using things like map and flatMap:

    val f1 = Future { "hello" }
    val f2 = f1.map(_ + " world")
    val f3 = f2.map(_.length)
    val result = Await.result(f3, 1 second)
    println(result) //  prints "11"
    

    Or use them in for-comprehensions:

    val f1 = Future { "hello" }
    val f2 = Future { " " }
    val f3 = Future { "world" }
    val f4 =
      for (
        a <- f1;
        b <- f2;
        c <- f3
      ) yield {
        a + b + c
      }
    val result = Await.result(f4, 1 second)
    println(result) //  prints "hello world"