Future as an effect

Future has all of the usual suspects that have been made known to us from this chapter so far. foreach allows us to define a callback to execute after the Future successfully completes:

scala> runningLong.foreach(_ => println("First callback"))
scala> runningLong.foreach(_ => println("Second callback"))
scala> Second callback
First callback

The order of execution is not guaranteed, as shown in the previous example.

There is another callback that is called for any completed feature, regardless of its success. It accepts a function, taking Try as a parameter:

scala> runningLong.onComplete {
| case Success(value) => println(s"Success with $value")
| case Failure(ex) => println(s"Failure with $ex")
| }
scala> Success with ()

The transform method is also applied in both cases. There are two flavors of it. One takes two functions, for Success and Failure, accordingly, and another takes one function, Try => Try:

stringFuture.transform(_.length, ex => new Exception(ex))
stringFuture.transform {
case Success(value) => Success(value.length)
case Failure(ex) => Failure(new Exception(ex))
}

In both cases, we transform the string to its length in the case of success and wrap an exception in the case of failure. The second variant is more flexible, though, as it allows us to convert success to failure and vice versa. 

This filtering is also done in the same way as with other effects, that is, with the filter and collect methods:

stringFuture.filter(_.length > 10)
stringFuture.collect {
case s if s.length > 10 => s.toUpperCase
}

The former just converts a Success into Failure(NoSuchElementException) (or leaves the existing Failure in place) if the predicate does not hold. The latter also modifies the contents to upper case for Success.

And of course, map and flatMap are available. We'll let our user service use Futures as an effect – this time to denote that every action, including our research for the best bite name for the fish, takes some time to finish:

val buyBait: String => Future[Bait]
val makeBait: String => Future[Bait]
val castLine: Bait => Future[Line]
val hookFish: Line => Future[Fish]

This brings us to the following, already familiar, implementation:

def goFishing(bestBaitForFish: Future[String]): Future[Fish] = for {
baitName <- bestBaitForFish
bait <- buyBait(baitName).fallbackTo(makeBait(baitName))
line <- castLine(bait)
fish <- hookFish(line)
} yield fish

It is easy to see that besides changes in the effect type, the only difference to the previous implementations is the use of the fallback method to provide an alternative in the case of an unsuccessful call of the buyBait method.

There is a lot more to cover about the Future and its dual Promise. We encourage you to take a look at the official documentation and related blog posts (for example  https://viktorklang.com/blog/Futures-in-Scala-2.12-part-9.html) for some examples of advanced usage.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.136.226