I have the following snippet in Scala using Scalaz and Task/EitherT:
def myMethod(request: MyRequest) : EitherT[Task, Failure, Success] =
EitherT[Task, Failure, Success](
for {
aamOpt <- async.findUser(request)
aamEith <- Task.now(aamOpt.\/>(NoUserFound()))
result <- aamEith.fold(err => Task.now(-\/(err)), aam => process(aam)).run)
} yield result)
Where async.findUser returns a Task[Option[MyUser]] and process(aam) returns EitherT[Task, Failure, Success]. These return types are needed as these methods interact (down the line) with external services.
Is there any way to simplify the last line of the for comprehension into something nicer? I mean this one:
result <- aamEith.fold(err => Task.now(-\/(err)), aam => process(aam)).run)
I would probably immediately lift the result from async.findUser into the relevant EitherT monad and then just flatMap:
def myMethod(request: MyRequest): EitherT[Task, Failure, Success] =
EitherT.eitherT[Task, Failure, MyUser](
async.findUser(request).map(_.\/>(NoUserFound()))
).flatMap(process)
This is untested but something like it should more or less work.
Related
Say I have a series of independent computations that need to be combined at the end:
def makeSauce(): Try[Sauce] = Success(Sauce("marinara"))
def makeCrust(): Try[Crust] = Failure(new RuntimeException("stale bread"))
def makeCheese(): Try[Cheese] = Failure(new IllegalArgumentException("moldy cheese"))
for {
sauce <- makeSauce()
crust <- makeCrust()
cheese <- makeCheese()
} yield {
Pizza(sauce, crust, cheese)
}
But if any of my computations fail, I want a comprehensive error message describing all of the failures, not just the first. The above code doesn't do what I want; it only shows me the first failure ("stale bread"). Instead, it should throw a super-error message combining both of the others, which could be a sequence of exception objects, sequence of string error messages, or even just one giant concatenated string.
Alternatively, instead of throwing the exception, it could be composed into a top-level Failure object:
(for {
sauce <- makeSauce()
crust <- makeCrust()
cheese <- makeCheese()
} yield (sauce, crust, cheese)) match {
case Success((sauce, crust, cheese)) => Pizza(sauce, crust, cheese)
case Failure(e) => throw e
}
The for-comprehension and the Try here are just for illustration; a working solution doesn't have to use for or Try. However, obviously the above syntax is expressive and clean, and almost does what I want, so ideally the solution will stick to it as closely as possible.
How can I achieve something like this in Scala?
Validated is what you are looking for. It is in Cats for example.
import cats.data.Validated
import cats.implicits.catsSyntaxTuple3Semigroupal
def valid(input: String) = if (input.toIntOption.isEmpty) Validated.Invalid(s"$input is not a number")
else Validated.Valid(input.toInt)
def sumThreeNumbers(one:String, two:String, three: String) = (valid(one), valid(two), valid(three)).mapN((oneInt, twoInt, threeInt)=> oneInt + twoInt + threeInt)
sumThreeNumbers("1","2","3")
sumThreeNumbers("1","two","xxx")
//results
val res0: cats.data.Validated[String,Int] = Valid(6)
val res1: cats.data.Validated[String,Int] = Invalid(two is not a number.xxx is not a number.)
scala.util.Try behaves in a fail-fast manner. In a for-comprehension context it executed sequentially and halts at the first failure.
What you need is a structure that aggregates all failures like cats.data.Validated or scalaz.Validation.
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}")
}
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].
What is the most idiomatic and concise way to perform the following: One future that may or may not execute depending or a result of a previous future execution, like so:
def getItFromHere : Future[Option[Something]] = ...
def getItFromThere : Future[Option[Something]] = ...
def getIt : Future[Option[Something]] = {
for {
maybeSomething <- getItFromHere
probablySomething <- maybeSomething.getOrElse(getItFromThere) // Obviously can't be done!!!
}
yield probablySomething
}
A specific use-case example:
Get an item from cache and only if it wasn't found in cache, get it from the database.
I'm taking an assumption here that getItFromHere and getItFromThere will not fail with an exception. They will either return Some[Something] or None. Feel free to take this assumption into account, or giving a better without it.
Note: I understand the internal mechanics of for-comprehension which is actually translated to map/flatMap/filter internally.
You could fail the future if no item is found in the cache and then recover it with the retrieval.
// assuming getItFromHere() fails if no item is found
getItFromHere() recoverWith { case _ => getItFromThere() }
Or with the Option you could do it like this:
getItFromHere() flatMap {
case Some(x) => Future.successful(Some(x))
case None => getItFromThere()
}
Actually your example is almost there. You only need to match the Future type expected by the monadic composition:
for {
fut <- someFuture
something <- fut.map(x=>someFuture).getOrElse(someBetterFuture)
} yield something
For the sake of simplicity, here someFuture is a val. If you use a def, avoid re-calculating the operation by packaging your result back into a future. Folding that into the question's code:
for {
maybeSomething <- getItFromHere
probablySomething <- maybeSomething.map(x=> Future.succcessful(maybeSomething)).getOrElse(getItFromThere)
} yield probablySomething
if you use the OptionT transformer from scalaz:
def getItFromHere : OptionT[Future,Something] = OptionT(...)
def getItFromThere : OptionT[Future,Something] = OptionT(...)
def getIt : Future[Option[Something]] = (getItFromHere orElse getItFromThere).run
Option monad is a great expressive way to deal with something-or-nothing things in Scala. But what if one needs to log a message when "nothing" occurs? According to the Scala API documentation,
The Either type is often used as an
alternative to scala.Option where Left
represents failure (by convention) and
Right is akin to Some.
However, I had no luck to find best practices using Either or good real-world examples involving Either for processing failures. Finally I've come up with the following code for my own project:
def logs: Array[String] = {
def props: Option[Map[String, Any]] = configAdmin.map{ ca =>
val config = ca.getConfiguration(PID, null)
config.properties getOrElse immutable.Map.empty
}
def checkType(any: Any): Option[Array[String]] = any match {
case a: Array[String] => Some(a)
case _ => None
}
def lookup: Either[(Symbol, String), Array[String]] =
for {val properties <- props.toRight('warning -> "ConfigurationAdmin service not bound").right
val logsParam <- properties.get("logs").toRight('debug -> "'logs' not defined in the configuration").right
val array <- checkType(logsParam).toRight('warning -> "unknown type of 'logs' confguration parameter").right}
yield array
lookup.fold(failure => { failure match {
case ('warning, msg) => log(LogService.WARNING, msg)
case ('debug, msg) => log(LogService.DEBUG, msg)
case _ =>
}; new Array[String](0) }, success => success)
}
(Please note this is a snippet from a real project, so it will not compile on its own)
I'd be grateful to know how you are using Either in your code and/or better ideas on refactoring the above code.
Either is used to return one of possible two meaningful results, unlike Option which is used to return a single meaningful result or nothing.
An easy to understand example is given below (circulated on the Scala mailing list a while back):
def throwableToLeft[T](block: => T): Either[java.lang.Throwable, T] =
try {
Right(block)
} catch {
case ex => Left(ex)
}
As the function name implies, if the execution of "block" is successful, it will return "Right(<result>)". Otherwise, if a Throwable is thrown, it will return "Left(<throwable>)". Use pattern matching to process the result:
var s = "hello"
throwableToLeft { s.toUpperCase } match {
case Right(s) => println(s)
case Left(e) => e.printStackTrace
}
// prints "HELLO"
s = null
throwableToLeft { s.toUpperCase } match {
case Right(s) => println(s)
case Left(e) => e.printStackTrace
}
// prints NullPointerException stack trace
Hope that helps.
Scalaz library has something alike Either named Validation. It is more idiomatic than Either for use as "get either a valid result or a failure".
Validation also allows to accumulate errors.
Edit: "alike" Either is complettly false, because Validation is an applicative functor, and scalaz Either, named \/ (pronounced "disjonction" or "either"), is a monad.
The fact that Validation can accumalate errors is because of that nature. On the other hand, / has a "stop early" nature, stopping at the first -\/ (read it "left", or "error") it encounters. There is a perfect explanation here: http://typelevel.org/blog/2014/02/21/error-handling.html
See: http://scalaz.googlecode.com/svn/continuous/latest/browse.sxr/scalaz/example/ExampleValidation.scala.html
As requested by the comment, copy/paste of the above link (some lines removed):
// Extracting success or failure values
val s: Validation[String, Int] = 1.success
val f: Validation[String, Int] = "error".fail
// It is recommended to use fold rather than pattern matching:
val result: String = s.fold(e => "got error: " + e, s => "got success: " + s.toString)
s match {
case Success(a) => "success"
case Failure(e) => "fail"
}
// Validation is a Monad, and can be used in for comprehensions.
val k1 = for {
i <- s
j <- s
} yield i + j
k1.toOption assert_≟ Some(2)
// The first failing sub-computation fails the entire computation.
val k2 = for {
i <- f
j <- f
} yield i + j
k2.fail.toOption assert_≟ Some("error")
// Validation is also an Applicative Functor, if the type of the error side of the validation is a Semigroup.
// A number of computations are tried. If the all success, a function can combine them into a Success. If any
// of them fails, the individual errors are accumulated.
// Use the NonEmptyList semigroup to accumulate errors using the Validation Applicative Functor.
val k4 = (fNel <**> fNel){ _ + _ }
k4.fail.toOption assert_≟ some(nel1("error", "error"))
The snippet you posted seems very contrived. You use Either in a situation where:
It's not enough to just know the data isn't available.
You need to return one of two distinct types.
Turning an exception into a Left is, indeed, a common use case. Over try/catch, it has the advantage of keeping the code together, which makes sense if the exception is an expected result. The most common way of handling Either is pattern matching:
result match {
case Right(res) => ...
case Left(res) => ...
}
Another interesting way of handling Either is when it appears in a collection. When doing a map over a collection, throwing an exception might not be viable, and you may want to return some information other than "not possible". Using an Either enables you to do that without overburdening the algorithm:
val list = (
library
\\ "books"
map (book =>
if (book \ "author" isEmpty)
Left(book)
else
Right((book \ "author" toList) map (_ text))
)
)
Here we get a list of all authors in the library, plus a list of books without an author. So we can then further process it accordingly:
val authorCount = (
(Map[String,Int]() /: (list filter (_ isRight) map (_.right.get)))
((map, author) => map + (author -> (map.getOrElse(author, 0) + 1)))
toList
)
val problemBooks = list flatMap (_.left.toSeq) // thanks to Azarov for this variation
So, basic Either usage goes like that. It's not a particularly useful class, but if it were you'd have seen it before. On the other hand, it's not useless either.
Cats has a nice way to create an Either from exception-throwing code:
val either: Either[NumberFormatException, Int] =
Either.catchOnly[NumberFormatException]("abc".toInt)
// either: Either[NumberFormatException,Int] = Left(java.lang.NumberFormatException: For input string: "abc")
in https://typelevel.org/cats/datatypes/either.html#working-with-exception-y-code