Given these three methods that return Future[Either[String,Int]]:
def greater(x:Int): Future[Either[String,Int]] = Future {
if (x>0)
Right(x)
else
Left("Is not greater")
}
def less(x:Int): Future[Either[String,Int]] = Future {
if (x<0)
Right(x)
else
Left("Is not less")
}
def zero(x:Int): Future[Either[String,Int]] = Future {
if (x==0)
Right(x)
else
Left("Is not zero")
}
The following method that invokes the three above throws a compilation error:
def evaluate(x:Int): Future[Either[String,Int]] = {
val future = greater(x)
future.flatMap { either =>
either.right.flatMap { response => // <-- error in this line
val future2 = less(response)
future2.map { either2 =>
either2.right.map { response2 => zero(response2) }
}
}
}
}
The error:
type mismatch; found : scala.util.Either[String,Nothing] required:
scala.concurrent.Future[Either[String,Int]]
How to fix the evaluate method?
Classic case of Monad transformers.
Use EitherT from cats
val result =
for {
a <- EitherT(greater(x))
b <- EitherT(less(a))
c <- EitherT(zero(b))
} yield c
final value: result.value
Why EitherT?
Either is inside the another seemingly monad Future. So, EitherT can be used.
Related
I have a method that processes a Source and returns. I am trying to modify it but can't seem to be able to return the same thing:
Original
def originalMethod[as: AS, mat: MAT, ec: EC](checkType: String)
: Flow[ByteString, MyValidation[MyClass], NotUsed]{
collectStuff
.map { ts =>
val errors = MyEngine.checkAll(ts.code)
(ts, errors)
}
.map { x =>
x._2
.leftMap(xs => {
addInformation(x._1, xs.toList)
})
.toEither
}
}
I am modifying by using another source and pass result of that to the original source and yet return the same thing:
def calculate[T: AS: MAT](source: Source[T, NotUsed]): Future[Seq[T]] =
{
source.runWith(Sink.seq)
}
def modifiedMethod[as: AS, mat: MAT, ec: EC](checkType: String, mySource: Source[LoanApplicationRegister, NotUsed])
: Flow[ByteString, MyValidation[MyClass], NotUsed]{
for {
calc <- calculate(mySource)
orig <- collectStuff
.map { ts =>
val errors = MyEngine.checkAll(ts.code, calc)
(ts, errors)
}
.map { x =>
x._2
.leftMap(xs => {
addInformation(x._1, xs.toList)
})
.toEither
}
}
yield {
orig
}
}
But I'm getting compilation error Expression of type Future[Nothing] doesn't conform to existing type Flow[ByteString, MyValidation[MyClass]
How can I return Flow[ByteString, MyValidation[MyClass] in my modifiedMethod just like the originalMethod was
for { calc <- calculate(mySource)}
yield {
collectStuff
.map { ts =>
val errors = MyEngine.checkAll(ts.code, calc)
(ts, errors)
}
.map { x =>
x._2
.leftMap(xs => {
addInformation(x._1, xs.toList)
})
.toEither
}
}
would give you a Future[Flow[ByteString, MyValidation[MyClass], NotUsed]] instead of Future[Nothing]
but if you want to remove the Future you'd need to Await somewhere for it (either when you call calculate (and then you don't need the for) or after it. Usually, that's not the way to use Futures
def myMethod(myType: String) :Future[Future[Either[List[MyError], MyClass]]] {
for {
first <- runWithSeq(firstSource)
}
yield {
runWithSeq(secondSource)
.map {s ->
val mine = MyClass(s.head, lars)
val errors = myType match {
case "all" => Something.someMethod(mine)
}
(s, errors)
}
.map { x =>
x._2.leftMap(xs => {
addInfo(x._1.head, xs.toList)
}).toEither
}
}
}
for {
myStuff <- myMethod("something")
} yield {
myStuff.collect {
case(Left(errors), rowNumber) =>
MyCaseClass(errors, None) //compilation error here
}
}
I get compilation error on MyCaseClass that expected: List[MyError], found: Any
The signature of MyCaseClass is:
case class MyCaseClass(myErrors: List[ValidationError])
How can I fix this such that I can correctly call MyCaseClass inside the yield?
Your code example doesn't make much sense, and doesn't compile, but if runWithSeq() returns a Future then you should be able to eliminate the double Future return type like so.
for {
_ <- runWithSeq(firstSource)
scnd <- runWithSeq(secondSource)
} yield { ...
Your example is pretty hard to paste and fix
Abstact example for this
Class C may be whatever you want
def test(testval: Int)(implicit ec: ExecutionContext): Future[Future[Either[String, Int]]] = {
Future(Future{
if (testval % 2 == 0) Right(testval) else Left("Smth wrong")
})
}
implicit class FutureEitherExt[A, B](ft: Future[Either[A, B]]) {
def EitherMatch[C](f1: A => C, f2: B => C)(implicit ec: ExecutionContext): Future[C] = {
ft.map {
case Left(value) => f1(value)
case Right(value) => f2(value)
}
}
}
val fl: Future[Either[String, Int]] = test(5).flatten
val result: Future[String] = fl.EitherMatch(identity, _.toString)
I'm getting the following compilation error in the future recover line:
type mismatch; found : scala.concurrent.Future[Any] required:
scala.concurrent.Future[play.api.mvc.Result]
I'm returning Ok() which is a Result object, so why is the compiler complaining?
class Test2 extends Controller {
def test2 = Action.async { request =>
val future = Future { 2 }
println(1)
future.map { result => {
println(2)
Ok("Finished OK")
}
}
future.recover { case _ => { // <-- this line throws an error
println(3)
Ok("Failed")
}
}
}
}
If you take closer look at the Future.recover method you'll see that partial function should have subtype of future's type, in your case Int, because you apply recover to original Future 'future'. To fix it you should apply it to mapped:
future.map {
result => {
println(2)
Ok("Finished OK")
}
}.recover {
case _ => {
println(3)
Ok("Failed")
}
}
You forget to chain, so do like Nyavro wrote, or, if you like another style, then just introduce an intermediate variable.
def test2 = Action.async { request =>
val future = Future { 2 }
println(1)
val futureResult = future.map { result => {
println(2)
Ok("Finished OK")
}}
futureResult.recover { case _ => {
println(3)
Ok("Failed")
}}
}
I have this code that I use in a spray handler
get {
def callService = {
val p = Promise[Option[DocumentRef]]
val fut = p.future
archiveService.getByHash(ZeroHash, {
result => p success result
})
fut
}
onComplete(OnCompleteFutureMagnet(callService)){
case Success(docRef) => {
val doc = docRef map {
x => x.title
} getOrElse "nothing"
complete("Done with " + doc)
}
case Failure(ex) => complete("error ${ex.getMessage}")
}
}
so I had the bright idea of writing the following function to encapsulate the work done to create a future out of a promise:
def callback2Future[T](funToCall: (T => Unit) => Any): Future[T] = {
val p = Promise[T]
val resultFuture = p future
def callbacklistener(arg: T): Unit = {
arg: T => p success arg
}
funToCall(callbacklistener)
resultFuture
}
And restructure the onComplete as:
onComplete(OnCompleteFutureMagnet(callback2Future(archiveService.getByHash(ZeroHash, _: Option[DocumentRef] => Unit)))) {
case Success(docRef) => {
...
}
In the original implementation with callservice, it works great (with great throughput too), with the callback2Future implementation I get a forever wait and it eventually times out. They seem the same to me, can anyone spot the error?
I believe that your problem is due to the infamous auto-Unit feature of Scala. Your function:
def callbacklistener(arg: T): Unit = {
arg: T => p success arg
}
will probably be interpreted as:
def callbacklistener(arg: T): Unit = {
{ arg: T => p success arg }
()
}
What you really want is probably:
def callbacklistener(arg: T): Unit = p success arg
To be clear, in your implementation you are defining a function callbackListener with return type Unit; in the body of this function you have an expression, { arg: T => p success arg }, whose value is of type T => Unit and is discarded; the Scala compiler will then put a free () in your code as the return type of the callbackListener is supposed to be Unit.
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