Try to understand scala syntax with blocks - scala

I'm a beginner in scala and I'm trying to understand this syntax :
val f = Future {
Thread.sleep(Random.nextInt(500))
42
}
println("2- before onComplete")
f.onComplete {
case Success(value) => println(s"Got the callback, meaning = $value")
case Failure(e) => e.printStackTrace
}
Please explain these 2 blocks inside Future{...} and onComplete{...}
Thanks a lot

The first block is equal to something like that:
def code(): Int = {
Thread.sleep(Random.nextInt(500))
42
}
val f = Future(code)
Block acts like an anonymous function but it not reuqires to declare a function, it is just a syntax sugar.
So future f eagerly evaluates contents of a block asynchronously starting at the point of declaration. I.e. if random will yield a number n which is 0 < n < 500, future execution will be suspended for n milliseconds and then resumed and number 42 will be returned and set as a result of a Future.
As futures are non-blocking, while execution context of your future working on your future f, the main thread will run line
println("2- before onComplete")
and you will see this line in the console.
Then, the second block uses pattern matching to create a function that acts from Try[Int] to Unit, as it defined on both Success and Failure constructors of Try, it is an equivalent to:
f.onComplete { ttry =>
ttry match {
case Success(value) => println(s"Got the callback, meaning = $value")
case Failure(e) => e.printStackTrace
}
}
Note that you must await your future till application termination to ensure onComplete block execution.

In scala every statement is expression. Blocks are expressions also. Every expression has return value. These blocks will do something in blocks and return some values.
In Future block, it creates Future object witch contains 2 operations: sleep for random milliseconds and returns 42. In onComplete method block means handling two cases of Future evaluation, on success and on failure statements. If future will throw an error or evaluation will interrupted, Failure case will evaluate. If future evaluated successfully Success case will evaluate. Return value in both cases is Unit it's analogue of void.

Related

What exactly is returned in a Scala Future?

I am new to Scala and am working on an application using akka and futures
I have a class(C) that processes a future and returns a List(L) of objects type X. X has a field y and it is this field I am interesed in. (Note: L was previously converted from a ListBuffer type).
In the Main Class that calls C the code to process the result is:
Snippet A:
result1.onComplete {
result =>
result.foreach(f = (o: List[X]) => {
o.foreach(f = (o: x) => {
println(X.y)
})
})
}
I can also use this code:
Snippet B:
result1 onSuccess{
case result =>
result.foreach(f = (o: X) => {
println(o.y)
})
}
Obviously, as OnSuccess is deprecated the first form may be preferred. The second form (Snippet B) I can understand, but I am baffled as to why, when using onComplete, I have to use nested 'foreach' to get to the same result. If anyone can help as I dont yet have a clear conception of what 'result' (Try[T] => U) ??? actually is. Thanks in advance..:)
If you take a look to the Future.onComplete scaladoc, you will see that it receives a function from Try[T], (where T is the type of your future), to Unit.
"When this future is completed, either through an exception, or a value, apply the provided function".
"Note that the returned value of f will be discarded".
The Try is there to catch failures on the asynchronous computation - that's why you need the two foreach, the first one is to extract the Successful List from the Try, and the second one is to extract each element O from the List.
You didn't need two in the case of onSuccess because, as the name says that callback would only be called if the Future completed successfully.
However, note that doing a foreach on a Try is a bad idea, since you are not handling the failure, also the code become hard to read - try this instead.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Success, Failure}
case class Result(data: Int)
val process: Future[List[Result]] =
Future.successful(List(Result(data = 5), Result(data = 3)))
process.onComplete {
case Success(results) =>
for (result <- results) {
println(result.data)
}
case Failure(ex) =>
println(s"Error: ${ex.getMessage}")
}

Future.onComplete never happens

I've got what seems like a fairly simple situation here:
I create a sequence of futures with yield of signature Future[(String, Date)]
I use Future.sequence to turn the IndexedSeq[Future[(String, Date)]] into a Future[IndexedSeq[(String, Date)]]
I call onComplete on that future to do something with each future after all of them have completed.
I'm doing this because the first wave are database inserts, I can't do the updateCalculatedField call until all inserts are completed, because updateCalculatedField involves aggregate functions and I don't want to introduce a race condition. Here's the code:
val initialInserts = for(i <- 0 until responseData.numValues()) yield { ... }
val res = Future.sequence(initialInserts)
res.onComplete{
case Success(seq) =>
for((i, d) <- seq)
updateCalculatedField(i, d)
case Failure(e) => e.printStackTrace()
}
What exactly am I doing wrong here? The code within the onComplete call never executes, and the program exits with no complaints. I've checked, and res.size is equal to the amount of rows in my database after the program exits... so the callback should have been executed. I'm at a loss here.
Thanks.

having trouble composing Scala Future from multiple Futures of different types

I have two functions: one returns a Future[Thing Or Exception] and another that returns Future[Boolean. I want a function that calls both and returns Future[Thing Or Exception]. If the boolean function returns false I want to return an exception, else the return of the other function.
I have code like this but a) I hate the cast and b) when run on the "boolean gets true" path I get this error when I eventually Await.result on the return in my test code: "Promise$DefaultPromise cannot be cast to org.scalatic.Or".
def thingFuture: Future[Thing Or Exception]
def boolFuture: Future[Boolean]
def combineFutures: Future[Thing Or Exception] = {
val result = boolFuture.map {x =>
x match {
case true => thingFuture
case false => Exception
}
}
// without the cast compiler says result is of type Future[Object]
result.asInstanceOf[Future[Thing Or Exception]]
}
I've also tried this but it gets the same Promise error on the success path
def combineFutures: Future[Thing Or Exception] = {
val result = boolFuture.map {x =>
x match {
case true => thingFuture.map { y =>
y match {
case Good(thing) => thing
case Bad(exception) => exception
}
case false => Exception
}
}
}
Can anyone tell me how to compose two futures with different return types? Thanks!
Every future can be completed with failed state in case exception has occurred, so you can simply return thingFuture in the "happy path" and throw an exception in case boolean is false. This will return a Future.failed with the underlying exception.
val result = boolFuture.flatMap {x =>
x match {
case true => thingFuture
case false => throw new Exception("whatever")
}
}
Note the flatMap instead of map. Because we map the underlying value of one future into a yet another future, by using simple map we would wind up with Future[Future[Thing]].
Also note that instead of throwing an exception, you could also return a Future.failed(throw new Exception("whatever")) and the result would be the same - in both case you get a failed future.
EDIT: I just realized Or comes from scalactic, which I never used, but the philosophy remains the same. You need to flatMap your boolean future and your ThingOrException future in order to wind up with Future[ThingOrException]. If you ever find yourself in a situation where you need to flatMap a Future, but one of the case clauses returns an ordinary value (e.g. in case of true return Future[Thing], in case of false return just Exception) then you can wrap the ordinary value into a future. This way all branches return a future and flatMap will work correctly. For example:
val someOtherFuture = Future(43)
val someOrdinaryValue = 44
Future(someInteger).flatMap {
case 42 => someOtherFuture
case _ => Future(someOrdinaryValue)
}
In order to simplify things for the runtime machinery a bit, you can also write Future.successful(someOrdinaryValue) in which case no background computation is started.
As far as I can tell from Scalatic documentation, you can get an instance of Right Or Left by either Good(Right) or Bad(Left).
That means the composition can potentially look like this:
boolFuture.flatMap(b => if (b) thingFuture else Future.successful(Bad(new Exception())))
The types should unify to Future[Or[Thing, Exception]]

Scala Futures - flatMap and onFailure

If I have some computation that takes a while I might place it in a scala.concurrent.Future:
val f = Future { someLongRunningFunction() }
and let's say I want to do something else asynchronously once that computation is completed:
f.flatMap{ _ => anotherLongRunningFunction() }
In the event that f's initial block fails, how do I "idiomatically" handle this when using flatMap or other combinators? Is it merely a case of using recover or onFailure before the flatMap?
I like the elegance and simplicity of using a flatMap but it seems failure scenarios get in the way of it.
Edit: the second future is reliant on the first, hence the flatMap. I'm looking for a solution that'll elegantly let me chain like I would with flatMap but also handle failures of the first.
To quote the scaladoc for flatMap:
Creates a new future by applying a function to the successful result
of this future, and returns the result of the function as the new
future. If this future is completed with an exception then the new
future will also contain this exception.
Notice the bold, meaning that whatever you pass to flatMap will only be executed if the initial future completes successfully.
So you should only handle the result of the entire execution:
val result = future1.flatMap {
result => functionReturningFuture2(result)
}
and then:
result.onFailure // or
result.onSuccess // or
result.recover
If you have several futures you can put them in a for comprehension.
val futureResult = for {
result1 <- future1
result2 <- future2
...
} yield {
//computation with results
}
You can add a recover at the end in case you want to process any exception you may find:
futureResult.recover{
case exceptionResult: Throwable => // Process exception
}
I think this is more clean that using flatMap.
I'm only starting with Future, but here are some ideas.
If you really want to use flatMap, you have to turn the failure into a success.
for{ a <- f recover r
b <- another(a)
} yield b
This works if the return type of r is :> the result type of f.
Or you can pass the problem of what to do with the failure on to the next process
for{ a <- f map (x => Success(x)) recover (ex => Failure(ex))
b <- another(a)
} yield b
Here the argument type of another would be Try[T] where the type of f is Future[T].

How does a for .. Yield strip out a Future?

I am struggling to understand how this code 'strips out' the Future.
getFutureResult() returns a Future[String]. So how come the return from the yield is only a String?
def getFutureResult:Future[String] = { ... }
def getMyResult:String = {
for {
myFutureResult <- getFutureResult()
} yield {
myFutureResult
}
}
It is translated according to Scala for-comprehension translation rules:
for (x <- <expr>) yield f(x)
becomes:
<expr>.map(x => f(x))
This is a desugaring done by the compiler irregardless if <expr> has the type of a collection, a future or something else.
Future in Scala has a method map, so it uses the myFutureResult String from above to construct another Future[String].
You never know if the resulting future getMyResult is completed -- you should install an onComplete callback that will be called by the resulting future once it completes:
getMyResult onComplete {
case Success(x) => println("Yes! " + x)
case Failure(t) => println("An error: " + t)
}
The code for the onComplete method is executed asynchronously -- it might happen on a different thread, much later or simultaneously.
If you really need to know if the Future has completed, use the:
Await(getMyResult, 0 nanos)
pattern to block the calling thread until the getMyResult future is completed. In general, you should avoid this and compose your Future code using for-comprehensions and callback.