I am trying to understand following answer How to carry on executing Future sequence despite failure?.
(Hope thats not a down vote worthy as i am trying to understand the code here.)
I dont understand how mapValue is transforming Future[T] to Future[Try[T]]
def mapValue[T]( f: Future[T] ): Future[Try[T]] = {
val prom = Promise[Try[T]]()
f onComplete prom.success
prom.future
}
the line f onComplete prom.success, what is it doing. My understanding was prom.success has to take an object of type Try[T] but here it does not do that. Also there is no assignment to f which transforms Future[T] to Future[Try[T]].
Moreover, anThen on Future is supposed to be a sideffect and is supposed to return the same future value that came into it, so not sure how does the transformation happen.
The f onComplete prom.success line is parsed by Scala compiler as following:
Dots and parentheses can be ommited in some cases, so f onComplete x is a way to write f.onComplete(x).
Compiler sees that onComplete method takes as argument function f: Try[T] => U. You also passed a function as an argument, Promise#success, which has a compatible signature.
So what the method is doing is creating a new Promise (writeable future) of type Try[T], and completing that promise with wrapped Try[T] as original future completes. Then it's returns new Future[Try[T]] obtained from promise.
To expand on Maxim's answer, f onComplete prom.success can be re-written as:
f.onComplete(prom.success)
or
f.onComplete(prom.success(_))
or
f.onComplete { resultOfFutureAsTry =>
prom.success(resultOfFutureAsTry)
}
prom.success sets the success value of the promise. Thus, no matter what happens inside the original future f, (an exception is thrown, or the future completes successfully), the new future (returned by prom.future, and created after the original future is completed) is always a successful future. Sometimes that successful future contains a Failure[T], and sometimes a Success[T].
Side note: Often, f.onComplete is used more like this:
f.onComplete {
case Success(x) => println(s"Yay, $x worked!")
case Failure(ex) => println(s"Darn, it failed: $ex")
}
But this is just a convenient way to write a function f: Try[T] => U.
Related
Given two futures f1 and f2, I'm trying to return the one that completes its execution first using this method:
def first[A](f1: Future[A], f2: Future[A]): Future[A] = ???
As an example of an implementation, a promise is used to fetch the first future that finish its computation, something like this:
def first[A](f1: Future[A], f2: Future[A]): Future[A] =
val promise = Promise[A]()
f1.onComplete(result1 => promise.tryComplete(result1))
f2.onComplete(result2 => promise.tryComplete(result2))
promise.future
But I was wondering, is there any other approach to this problem that doesn't use the onComplete() method? (e.g., using the map() or flatMap() methods instead).
How would this implementation look like?
That's it, thanks so much for the help! I'm a newbie in this futures topic in Scala so I'm struggling a lil' bit with this. Have a nice day!
I was suggested to use Future[Book] rather than Future[Try[Book]] in a pull request review.
Why is that?
If I use Future[Book], then how I can convert Success or Failure. Is it not clear to me at all.
If we use Future[Book], we are completely losing the notion of success and failure in Scala.
In Scala, the resulting value of a future is wrapped in either a Success or Failure type, which is a type of Try. Hence, the value in a Future is always an instance of one of the Try types: Success or Failure.
Since these are Try types, you can register a callback on a future which accepts a Try type. An example is to use the onComplete which takes a callback function of type Try[T] => U and returns a Unit.
import scala.util.{Success, Failure}
val f: Future[List[String]] = Future {
session.getUserNamesFromDatabase
}
f onComplete {
case Success(users) => for (user <- users) println(user)
case Failure(t) => println("An error has occurred: " + t.getMessage)
}
The benefit of a callback on a future is that it can complete without blocking the client. So the callback can execute completely asynchronously.
Note: that the onComplete method has a unit return type. So it cannot be chained.
In scala concurrent package, there is onComplete method which returns nothing while in akka-http directives, it returns the Directive1.
Is that the only difference? I sometimes got confused on those two methods.
These methods are different in what they aim to accomplish, but they are related in that the akka http onComplete is meant to work with the completion of a Future in order to complete the routing of a request.
The concurrent onComplete is a method on a Future that is meant to perform some sort of side effecting when the Future has completed. There are a lot of other methods on a Future like map, flatMap and filter that will produce another Future as you go through a series of transforms, but onComplete returns nothing, and is sort of a "dead end" in the processing of that Future.
An example of using onComplete while also showing how something like map can be used to change the Future is as follows:
val fut1 = Future{"1"} // A Future[String]
val fut2 = fut1.map(_.toInt) // Now a Future[Int]
fut2.onComplete{
case util.Success(i) => println(s"success: $i")
case util.Failure(ex) => ex.printStackTrace()
}
val badFut1 = Future{"A"}
val badFut2 = badFut.map(_.toInt) //Will be failed
badFut2.onComplete{
case util.Success(i) => println(s"success: $i")
case util.Failure(ex) => ex.printStackTrace()
}
In the first case, we will hit the success case as "1" can be mapped into an Int. In the second example, we will hit the error case as "A" cannot be mapped to an Int. Either way, you can see that something like map can be used to create a new transformed future while onComplete can be used to do something based on the final result of that Future.
In Akka Http, you sometimes need to create Route definitions that need to do something asynchronously. In that case, you need to complete the route when that asynchronous task completed. A Route itself needs to be fully defined in order to compile, so you can't leverage the existing onComplete on a Future because that returns nothing and that would render the definition of that Route as incomplete. Therefore, the guys at Akka defined an onComplete directive that will snap into a routing tree and work with a Future, returning a Directive that will fully define the tree for that Route as oppose to leaving it open ended as the Future.onComplete would. An example:
val myRoute =
get{
val fut = myActor ? "foo"
onComplete(foo){
case util.Success(_) => complete(StatusCodes.OK)
case util.Failure(ex) => complete(StatusCodes.InternalServerError)
}
}
So here, I'm making a request to an Actor using ask (?) and I get a Future back. I still need to produce something that completes the Route I am defining. If I did something like this:
val myRoute =
get{
val fut = myActor ? "foo"
fut.onComplete{
case util.Success(_) => complete(StatusCodes.OK)
case util.Failure(ex) => complete(StatusCodes.InternalServerError)
}
}
It worn't work because the onComplete here is the one from the Future and not the directive, and that returns Unit and my Route won't be full defined and won't compile.
So the onComplete directive is there to allow you to define a Route based on the completion of a Future which you can't do properly with the pre-existing onComplete from Future itself.
Taking in account that any pattern matching on Future result matches Success[A] and Failure[A] (onComplete(), andThen()) (because they expect Try[A] as an argument, directly or through partial function), could there be a case when I would want to say explicitly that a function is of type Future[Try[A]]?
There are various constructs in Scala which carry failure case in them. There are Option, Either, Try and Future. (Futures main point is to abstract asynchronous operations, an error handling is there for convinience). Scalaz have even more: Validation (Disjunction and Maybe are better Either and Option).
They all have a bit different treatment of erroneous values. Yet Try and Future have very similar, both wrap Throwable. So IMHO, Future[Try[A]] doesn't add much information (about the error). Compare to having Future[Future[A]] or Try[Try[A]]. OTOH Future[Option[A]] or Future[Either[MyError, A]] make sense to me.
There might be sitatuon where you have for example potentially failing f: A => B and g: B => C and you'd like to avoid creating too much tasks in the ExecutionContext:
val a: Future[A] = ???
val c: Future[C] = a.map(f).map(g) // two tasks, not good
val c2: Future[Try[C]] = a.map(x => Try { f(x) } map g ) // one task, maybe better
// get will throw, but exception will be catched by Future's map
// Almost no information is lost compared to `c2`
// You cannot anymore distinguish between possible error in `a`
// and exceptions thrown by `f` or `g`.
val c3: Future[C] = a.map(x => Try { f (x) }.map(g).get)
In this case, I'd rather refactor f and g to have better types, at least: f: A => Option[B] and g: B => Option[C] then, ending up with Future[Option[C]].
Try[A] represents a synchronous computation that may fail.
Future[A] represents an asynchronous computation that may fail.
Under this definitions, Future[Try[A]] represents the result of a synchronous computation (that may fail) executed inside of an asynchronous computation (that may fail).
Does it make sense? Not to me, but I'm open to creative interpretations.
trait Future[T]{
def onComplete( callback: Try[T] => Unit )(...):Unit
}
trait Socket{
def sendToEurope( packet:Array[Byte] ):Future[Array[Byte]]
}
val c:Future[Array[Byte]] = packet onComplete {
case Success(p) => socket.sendToEurope(p)
....
}
this a sample quoted from the class note of coursera "Reactive programming"
I was trying to understanding the method signature here. onComplete takes a Try => Unit function type, while the bracket section is a Success=>FutureType. I don't see how the 2 types are compatible here. Taking variance into consideration: Function1[-A,+R] which makes Success compatible, but I still don't see Future covariant with Unit here.
can someone explain this to me ?
Your understanding of the code is correct, that it does not compile.
Future.onComplete returns a Unit and therefore cannot return a Future[Array[Byte]] despite it being return type of socket.sendToEurope.
The code is correct. Any value will be automatically converted to Unit if Unit is the expected type. The rule is there for these types of situations, where otherwise you would have to do:
val c:Future[Array[Byte]] = packet onComplete {
case Success(p) => socket.sendToEurope(p); ()
....
}
Which would be ugly.
See Scala: Why can I convert Int to Unit?