replace a while loop with Future in scala - scala

I have a function with return value of Future[Int]
def func: Future[Int] = {...}
I will periodically check the return value of func until it meet some condition(e.g. return value greater than 10), then I will take use of this return value to create other future value with map/flatmap.
How can I make this work without any synchronous code? which is listed below:
def check: Future[Int] = {
var ret: Int = Await.result(func, Duration.Inf)
while (ret <= 10) {
ret = Await.result(func, Duration.Inf)
}
Future(ret + 100)
}

One way to achieve this is using recursion as shown below.
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
def check(func: () => Future[Int]): Future[Int] = {
Future.unit.flatMap(_ => func()) flatMap {
case x if x <= 10 => check(func)
case x => Future.successful(x + 100)
}
}

Related

Call a method that returns future n times

I want to call a method n times. Every subsequent call should be made only if the previous call was a success. This method returns a future. The code I attempted looks like this
def doSomething: Future[R] = Future {
//some logic
???
}
def outer() = {
val range = { 1 to 5 }
def inner(range: Seq[Int]): Future[R]=
range.headOption match {
case Some(head) =>
doSomething.flatMap { _ => inner(range.tail)}
case None => ???
}
inner(range)
}
In case None, I want to return the value of the last future that ran. How do achieve this?
Something like this?
// assumes that implicit ExecutionContext is available
// if it isn't available here add it to signature
def callMeNTimes[T](n: Int)(future: => Future[T]): Future[T] =
if (n <= 0) Future.failed(new Exception("Cannot run future less that 1 times"))
else if (n == 1) future
else future.flatMap(_ => callMeNTimes(n-1)(future))
callMeNTimes(5)(doSomething)
If you need to aggregate results across runs you could do something like:
def repeat[A](n: Int, init: A)(future: A => Future[A]): Future[A] =
if (n <= 0) Future.successful(init)
else future(init).flatMap(a => repeat(n-1, a)(future))

How to resolve a Future inside another Future

I want to create a function similar to the following. Basically the function, say F will create a Future say fut1. When fut1 resolves, then another Future say fut2 should get created inside fut1. The fut2 should return the final value of the function F. The code has to be non-blocking all the way. I have written something like this but the return type is not Future[Int] but Future[Future[Int]]. I understand why this is the case (because map creates a Future) but I am unable to figure out how to return Future[Int] from this code.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
def fut:Future[Int] = {
val f1 = Future{ 1 } //create a Future
f1.map (x => { //when f1 finishes, create another future
println(x)
val f2 = Future{ 2 }
f2.map(x=> x) //this creates another Future and thus the return is Future[Future[Int]]
})
}
You can achieve this using flat map or for comprehension.
FlatMap-
def futureFunctionWithFlatMap: Future[Int] = {
val f1 = Future {
1
}
f1.flatMap(x => {
println(x)
val f2 = Future {
2
}
f2.map(x => x)
})
}
For Comprehension
def futureFunctionWithForComprehension: Future[Int] = {
for {
f1 <- Future { 1 }
f2 <- {
println(f1)
Future { 2 }
}
} yield f2
}
Use flatMap
val f1 = Future{ 1 } //create a Future
val f2: Future[Int] = f1.flatMap(x => {
//will be triggered only after x is ready
Future{2}
})

Returning two Scala futures when both end

The method1 below is an attempt to return the results of two Future methods someFutureMethod1 and someFutureMethod2 combined. Any ideas how to make this work? Ideally the method that ends first should wait until the second ends, and then return the future values combined.
def method1 ( s: Seq[Int]): Future [(Int,Int)] = {
s.map { sx =>
val future = someFutureMethod1 (sx)
future.map {
result => result
}
val future2 = someFutureMethod2 (sx)
future2.map {
result2 => result2
}
(result,result2) // <-- the method should return the two results in the future
}
}
def someFutureMethod1 (i: Int) = Future {
i + 1
}
def someFutureMethod2 (i: Int) = Future {
i + 2
}
You combine Future's in a map, so it looks like you have to return a Seq of such Future's:
def method1 ( s: Seq[Int]): Seq[Future [(Int,Int)]] =
s.map { sx =>
val future = someFutureMethod1 (sx)
val future2 = someFutureMethod2 (sx)
future.zip(future2)
}

how to return value from a if block in scala

I want to return an integer type from an if block like in this sample code:
def a {
val res = if (1 == 1) {
val x = 1
b(x)
}
}
def b(x:Int) = {
20
}
Here the type of res is val res: AnyVal
How can I change it to Int?
If you don't have a default value to return, then you could return an Option[Int] instead, and combine this with getOrElse:
def a(n: Int): Option[Int] = {
if (n < 100) {
Some(n * 2)
} else {
None
}
}
a(10).getOrElse("Something else")
Another possibility is to use partial functions, because in your case your first function does not cover all cases, and you want to have a fallback:
val a: PartialFunction[Int, Int] = {
case n if n < 100 =>
n * 2
}
val b: PartialFunction[Int, String] = {
case _ =>
"Something else"
}
Then you can use applyOrElse:
// If function a is not defined for the input, then call function b
val result = a.applyOrElse(10, b)
or combine both partial functions into another function, and call that one:
// Combine a and b
val cf = a.orElse(b)
// Call
val result = cf(10)
You have to add else alternative, for example:
def a {
val res = if (1 == 1) {
val x = 1
b(x)
} else 0
}
This happens because for absent else case compiler uses Unit. And nearest common type for Int and Unit is AnyVal.
The reason you didn't get a determined int is that: your if block miss some code path. So if you change to:
val res = if (i == 1) {
val x = 1
b(x)
} else {
0 // some default value
}
That will be fine.
To have an immutable value val res well-defined with an if-else expression, both parts of the expression need be declared, as aforementioned. Even in the case of a mutable variable
var res: Int = _
the compiler instantiates it to a default 0. Thereafter it is valid for instance to
if (1 == 1) res = 20
without having to define the else part.

What is best way to wrap blocking Try[T] in Future[T] in Scala?

Here is the problem, I have a library which has a blocking method return Try[T]. But since it's a blocking one, I would like to make it non-blocking using Future[T]. In the future block, I also would like to compute something that's depend on the origin blocking method's return value.
But if I use something like below, then my nonBlocking will return Future[Try[T]] which is less convince since Future[T] could represent Failure[U] already, I would rather prefer propagate the exception to Future[T] is self.
def blockMethod(x: Int): Try[Int] = Try {
// Some long operation to get an Int from network or IO
throw new Exception("Network Exception") }
}
def nonBlocking(x: Int): Future[Try[Int]] = future {
blockMethod(x).map(_ * 2)
}
Here is what I tried, I just use .get method in future {} block, but I'm not sure if this is the best way to do that.
def blockMethod(x: Int): Try[Int] = Try {
// Some long operation to get an Int from network or IO
throw new Exception("Network Exception") }
}
def nonBlocking(x: Int): Future[Int] = future {
blockMethod(x).get * 2
}
Is this correct way to do that? Or there is a more scala idiomatic way to convert t Try[T] to Future[T]?
Here's an example that doesn't block, note that you probably want to use your own execution context and not scala's global context:
import scala.util._
import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global
object Main extends App {
def blockMethod(x: Int): Try[Int] = Try {
// Some long operation to get an Int from network or IO
Thread.sleep(10000)
100
}
def tryToFuture[A](t: => Try[A]): Future[A] = {
future {
t
}.flatMap {
case Success(s) => Future.successful(s)
case Failure(fail) => Future.failed(fail)
}
}
// Initiate long operation
val f = tryToFuture(blockMethod(1))
println("Waiting... 10 seconds to complete")
// Should return before 20 seconds...
val res = Await.result(f, 20 seconds)
println(res) // prints 100
}
In my opinion: Try & Future is a monadic construction and idiomatic way to is monadic composition (for-comprehension):
That you need to define monad transformer for Future[Try[_]] (code for your library):
case class FutureT[R](run : Future[Try[R]])(implicit e: ExecutionContext) {
def map[B](f : R => B): FutureT[B] = FutureT(run map { _ map f })
def flatMap[B](f : R => FutureT[B]): FutureT[B] = {
val p = Promise[Try[B]]()
run onComplete {
case Failure(e) => p failure e
case Success(Failure(e)) => p failure e
case Success(Success(v)) => f(v).run onComplete {
case Failure(e) => p failure e
case Success(s) => p success s
}
}
FutureT(p.future)
}
}
object FutureT {
def futureTry[R](run : => Try[R])(implicit e: ExecutionContext) =
new FutureT(future { run })
implicit def toFutureT[R](run : Future[Try[R]]) = FutureT(run)
implicit def fromFutureT[R](futureT : FutureT[R]) = futureT.run
}
and usage example:
def blockMethod(x: Int): Try[Int] = Try {
Thread.sleep(5000)
if(x < 10) throw new IllegalArgumentException
else x + 1
}
import FutureT._
// idiomatic way :)
val async = for {
x <- futureTry { blockMethod(15) }
y <- futureTry { blockMethod(25) }
} yield (x + y) * 2 // possible due to using modan transformer
println("Waiting... 10 seconds to complete")
val res = Await.result(async, 20 seconds)
println(res)
// example with Exception
val asyncWithError = for {
x <- futureTry { blockMethod(5) }
y <- futureTry { blockMethod(25) }
} yield (x + y) * 2 // possible due to using modan transformer
// Can't use Await because will get exception
// when extract value from FutureT(Failure(java.lang.IllegalArgumentException))
// no difference between Failure produced by Future or Try
asyncWithError onComplete {
case Failure(e) => println(s"Got exception: $e.msg")
case Success(res) => println(res)
}
// Output:
// Got exception: java.lang.IllegalArgumentException.msg