Search code examples
scalatwitterfinagletwitter-finagletwitter-util

What are advantages of a Twitter Future over a Scala Future?


I know a lot of reasons for Scala Future to be better. Are there any reasons to use Twitter Future instead? Except the fact Finagle uses it.


Solution

  • Disclaimer: I worked at Twitter on the Future implementation. A little bit of context, we started our own implementation before Scala had a "good" implementation of Future.

    Here're the features of Twitter's Future:

    • Some method names are different and Twitter's Future has some new helper methods in the companion.

    e.g. Just one example: Future.join(f1, f2) can work on heterogeneous Future types.

    Future.join(
      Future.value(new Object), Future.value(1)
    ).map {
      case (o: Object, i: Int) => println(o, i)
    }
    

    o and i keep their types, they're not casted into the least common supertype Any.

    • A chain of onSuccess is guaranteed to be executed in order: e.g.:

      f.onSuccess { 
        println(1) // #1
      } onSuccess { 
        println(2) // #2
      }
      

    #1 is guaranteed to be executed before #2

    • The Threading model is a little bit different. There's no notion of ExecutionContext, the Thread that set the value in a Promise (Mutable implementation of a Future) is the one executing all the computations in the future graph. e.g.:

      val f1 = new Promise[Int]
      f1.map(_ * 2).map(_ + 1)
      f1.setValue(2) // <- this thread also executes *2 and +1
      
    • There's a notion of interruption/cancellation. With Scala's Futures, the information only flows in one direction, with Twitter's Future, you can notify a producer of some information (not necessarily a cancellation). In practice, it's used in Finagle to propagate the cancellation of a RPC. Because Finagle also propagates the cancellation across the network and because Twitter has a huge fan out of requests, this actually saves lots of work.

      class MyMessage extends Exception
      
      val p = new Promise[Int]
      p.setInterruptHandler {
        case ex: MyMessage => println("Receive MyMessage")
      }
      
      val f = p.map(_ + 1).map(_ * 2)
      f.raise(new MyMessage) // print "Receive MyMessage"
      
    • Until recently, Twitter's Future were the only one to implement efficient tail recursion (i.e. you can have a recursive function that call itself without blowing up you call stack). It has been implemented in Scala 2.11+ (I believe).