This might be a really dumb question but I am trying to understand the logic behind using #flatMap and not just #map in this method definition in Finatra's HttpClient definition:
def executeJson[T: Manifest](request: Request, expectedStatus: Status = Status.Ok): Future[T] = {
execute(request) flatMap { httpResponse =>
if (httpResponse.status != expectedStatus) {
Future.exception(new HttpClientException(httpResponse.status, httpResponse.contentString))
} else {
Future(parseMessageBody[T](httpResponse, mapper.reader[T]))
.transformException { e =>
new HttpClientException(httpResponse.status, s"${e.getClass.getName} - ${e.getMessage}")
}
}
}
}
Why create a new Future when I can just use #map and instead have something like:
execute(request) map { httpResponse =>
if (httpResponse.status != expectedStatus) {
throw new HttpClientException(httpResponse.status, httpResponse.contentString)
} else {
try {
FinatraObjectMapper.parseResponseBody[T](httpResponse, mapper.reader[T])
} catch {
case e => throw new HttpClientException(httpResponse.status, s"${e.getClass.getName} - ${e.getMessage}")
}
}
}
Would this be purely a stylistic difference and using Future.exception is just better style in this case, whereas throwing almost looks like a side-effect (in reality it's not, as it doesn't exit the context of a Future) or is there something more behind it, such as order of execution and such?
Tl;dr:
What's the difference between throwing within a Future vs returning a Future.exception?
From a theoretical point of view, if we take away the exceptions part (they cannot be reasoned about using category theory anyway), then those two operations are completely identical as long as your construct of choice (in your case Twitter Future) forms a valid monad.
I don't want to go into length over these concepts, so I'm just going to present the laws directly (using Scala Future):
import scala.concurrent.ExecutionContext.Implicits.global
// Functor identity law
Future(42).map(x => x) == Future(42)
// Monad left-identity law
val f = (x: Int) => Future(x)
Future(42).flatMap(f) == f(42)
// combining those two, since every Monad is also a Functor, we get:
Future(42).map(x => x) == Future(42).flatMap(x => Future(x))
// and if we now generalise identity into any function:
Future(42).map(x => x + 20) == Future(42).flatMap(x => Future(x + 20))
So yes, as you already hinted, those two approaches are identical.
However, there are three comments that I have on this, given that we are including exceptions into the mix:
Be careful - when it comes to throwing exceptions, Scala Future (probably Twitter too) violates the left-identity law on purpose, in order to trade it off for some extra safety.
Example:
import scala.concurrent.ExecutionContext.Implicits.global
def sneakyFuture = {
throw new Exception("boom!")
Future(42)
}
val f1 = Future(42).flatMap(_ => sneakyFuture)
// Future(Failure(java.lang.Exception: boom!))
val f2 = sneakyFuture
// Exception in thread "main" java.lang.Exception: boom!
As #randbw mentioned, throwing exceptions is not idiomatic to FP and it violates principles such as purity of functions and referential transparency of values.
Scala and Twitter Future make it easy for you to just throw an exception - as long as it happens in a Future context, exception will not bubble up, but instead cause that Future to fail. However, that doesn't mean that literally throwing them around in your code should be permitted, because it ruins the structure of your programs (similarly to how GOTO statements do it, or break statements in loops, etc.).
Preferred practice is to always evaluate every code path into a value instead of throwing bombs around, which is why it's better to flatMap into a (failed) Future than to map into some code that throws a bomb.
Keep in mind referential transparency.
If you use map instead of flatMap and someone takes the code from the map and extracts it out into a function, then you're safer if this function returns a Future, otherwise someone might run it outside of Future context.
Example:
import scala.concurrent.ExecutionContext.Implicits.global
Future(42).map(x => {
// this should be done inside a Future
x + 1
})
This is fine. But after completely valid refactoring (which utilizes the rule of referential transparency), your codfe becomes this:
def f(x: Int) = {
// this should be done inside a Future
x + 1
}
Future(42).map(x => f(x))
And you will run into problems if someone calls f directly. It's much safer to wrap the code into a Future and flatMap on it.
Of course, you could argue that even when using flatMap someone could rip out the f from .flatMap(x => Future(f(x)), but it's not that likely. On the other hand, simply extracting the response processing logic into a separate function fits perfectly with the functional programming's idea of composing small functions into bigger ones, and it's likely to happen.
From my understanding of FP, exceptions are not thrown. This would be, as you said, a side-effect. Exceptions are instead values that are handled at some point in the execution of the program.
Cats (and i'm sure other libraries, too) employs this technique too (https://github.com/typelevel/cats/blob/master/core/src/main/scala/cats/ApplicativeError.scala).
Therefore, the flatMap call allows the exception to be contained within a satisfied Future here and handled at a later point in the program's execution where other exception value handling may also occur.
Related
I am trying to understand the difference why someone will use Future.successful(Failure(ServiceException("error"))) rather than Future.failed(ex) in Scala.
Future.successful(
Failure(
ServiceException(ErrorTypes.Validation, "Value should not be more than 30")
)
)
It's hard to say why the author did what they did, I can guess a couple of reasons:
They are not aware that you can Future.fail to return a failed future. This may happen because the signature of future doesn't convey the failure path explicitly in the type. When you see Future[A], you may think this computation must succeed in the future
They wanted to be explicit about failure. When I declare Future[Try[A]], I am forcing the caller to deal with the fact that can't directly access A, but have to "jump another hop" to get inside for A. Although this is delicate, as one can easily write:
val f: Future[Try[String]] = ???
f.map(_.map(str => // stuff with string))
But perhaps the signature forces the caller to realize the possibility of failure. Although Try is pretty limiting in it's expressiveness as well, as it can only return a Throwable on the failure path. I find Future[Either[E, A]] to be more expressive in that regards, which allows you to build your own failure hierarchy and encode it in the type.
There is an ever lasting debate regarding unary functor IO types (Future[A]) vs bi-functor IO types (IO[E, A], i.e. ZIO). I am in favor of bi-functor and have been using it solely recently, and I find it to be really time-saving when I don't have to dig into the implementation to understand the possible failures of a computation.
I would like to add on top of the great answer by #YuvalItzchakov, that writing code as in your question complicates the code and makes it unnatural. For example, let's assume that this future normally an Int, something like:
val succeeded = true // or any other computation
val future = if(succeeded) {
Future.successful(42)
} else {
Future.successful(Failure(new Exception("some failure text")))
}
Then first, the type of future is Future[Any], because Any is the lowest common root of Int and Failure, which is not convenient. But then, to map on it, you need to do:
future.map {
case i: Int =>
println(i)
case Failure(ex) =>
println(ex.getMessage)
} recover {
case NonFatal(ex) =>
println(s"recover ${ex.getMessage}")
}
Which feels weird to pattern match Int and Failure in the same match case. If you do want to pattern match Success and Failure, we had to do:
val succeeded = true // or any other computation
val future = if(succeeded) {
Future.successful(Success(42))
} else {
Future.successful(Failure(new Exception("some failure text")))
}
But that is already pretty clear as redundancy, right? No one will call Future.successful(Success(42)). So I think that it is pretty clear to use Future.failed(new Exception("some failure text")).
I am a new to Scala coming from Java background, currently confused about the best practice considering Option[T].
I feel like using Option.map is just more functional and beautiful, but this is not a good argument to convince other people. Sometimes, isEmpty check feels more straight forward thus more readable. Is there any objective advantages, or is it just personal preference?
Example:
Variation 1:
someOption.map{ value =>
{
//some lines of code
}
} orElse(foo)
Variation 2:
if(someOption.isEmpty){
foo
} else{
val value = someOption.get
//some lines of code
}
I intentionally excluded the options to use fold or pattern matching. I am simply not pleased by the idea of treating Option as a collection right now, and using pattern matching for a simple isEmpty check is an abuse of pattern matching IMHO. But no matter why I dislike these options, I want to keep the scope of this question to be the above two variations as named in the title.
Is there any objective advantages, or is it just personal preference?
I think there's a thin line between objective advantages and personal preference. You cannot make one believe there is an absolute truth to either one.
The biggest advantage one gains from using the monadic nature of Scala constructs is composition. The ability to chain operations together without having to "worry" about the internal value is powerful, not only with Option[T], but also working with Future[T], Try[T], Either[A, B] and going back and forth between them (also see Monad Transformers).
Let's try and see how using predefined methods on Option[T] can help with control flow. For example, consider a case where you have an Option[Int] which you want to multiply only if it's greater than a value, otherwise return -1. In the imperative approach, we get:
val option: Option[Int] = generateOptionValue
var res: Int = if (option.isDefined) {
val value = option.get
if (value > 40) value * 2 else -1
} else -1
Using collections style method on Option, an equivalent would look like:
val result: Int = option
.filter(_ > 40)
.map(_ * 2)
.getOrElse(-1)
Let's now consider a case for composition. Let's say we have an operation which might throw an exception. Additionaly, this operation may or may not yield a value. If it returns a value, we want to query a database with that value, otherwise, return an empty string.
A look at the imperative approach with a try-catch block:
var result: String = _
try {
val maybeResult = dangerousMethod()
if (maybeResult.isDefined) {
result = queryDatabase(maybeResult.get)
} else result = ""
}
catch {
case NonFatal(e) => result = ""
}
Now let's consider using scala.util.Try along with an Option[String] and composing both together:
val result: String = Try(dangerousMethod())
.toOption
.flatten
.map(queryDatabase)
.getOrElse("")
I think this eventually boils down to which one can help you create clear control flow of your operations. Getting used to working with Option[T].map rather than Option[T].get will make your code safer.
To wrap up, I don't believe there's a single truth. I do believe that composition can lead to beautiful, readable, side effect deferring safe code and I'm all for it. I think the best way to show other people what you feel is by giving them examples as we just saw, and letting them feel for themselves the power they can leverage with these sets of tools.
using pattern matching for a simple isEmpty check is an abuse of pattern matching IMHO
If you do just want an isEmpty check, isEmpty/isDefined is perfectly fine. But in your case you also want to get the value. And using pattern matching for this is not abuse; it's precisely the basic use-case. Using get allows to very easily make errors like forgetting to check isDefined or making the wrong check:
if(someOption.isEmpty){
val value = someOption.get
//some lines of code
} else{
//some other lines
}
Hopefully testing would catch it, but there's no reason to settle for "hopefully".
Combinators (map and friends) are better than get for the same reason pattern matching is: they don't allow you to make this kind of mistake. Choosing between pattern matching and combinators is a different question. Generally combinators are preferred because they are more composable (as Yuval's answer explains). If you want to do something covered by a single combinator, I'd generally choose them; if you need a combination like map ... getOrElse, or a fold with multi-line branches, it depends on the specific case.
It seems similar to you in case of Option but just consider the case of Future. You will not be able to interact with the future's value after going out of Future monad.
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Promise
import scala.util.{Success, Try}
// create a promise which we will complete after sometime
val promise = Promise[String]();
// Now lets consider the future contained in this promise
val future = promise.future;
val byGet = if (!future.value.isEmpty) {
val valTry = future.value.get
valTry match {
case Success(v) => v + " :: Added"
case _ => "DEFAULT :: Added"
}
} else "DEFAULT :: Added"
val byMap = future.map(s => s + " :: Added")
// promise was completed now
promise.complete(Try("PROMISE"))
//Now lets print both values
println(byGet)
// DEFAULT :: Added
println(byMap)
// Success(PROMISE :: Added)
I'm new to Scala, being slightly confused at the various ways to handle exceptions and looking for best-practice advice on the topic. I'm writing a simple method to retrieve a Customer using an existing blocking SDK. The possible outcomes are:
Customer is found
Customer is not found (comes back as a NotFoundException from the SDK)
Error while talking to remote server (SDK throws some other exception)
So I want my method to have a return type Future[Option[Customer]], and return for each case above:
Successful Future: Some(customer)
Successful Future: None
Failed Future
Here is what I wrote using try/catch:
private def findCustomer(userId: Long): Future[Option[Customer]] = future {
try {
Some(gateway.find(userId))
} catch {
case _: NotFoundException => None
}
}
This works fine and seems clean to me, but doesn't seem to be really the "Scala way" to do it - I've been told to avoid using try/catch. So I've been looking for a way to rewrite it using a Try instead.
Here are 2 variants that (I think) behave exactly the same, using a Try.
Variant A:
private def findCustomer(userId: Long): Future[Option[Customer]] = future {
Try(
Some(gateway.find(userId))
).recover {
case _: NotFoundException => None
}.get
}
Variant B:
private def findCustomer(userId: Long): Future[Option[Customer]] = future {
Try(
Some(gateway.find(userId))
).recover {
case _: NotFoundException => None
}
} flatMap {
case Success(s) => Future.successful(s)
case Failure(f) => Future.failed(f)
}
I'm not a huge fan of A (even though it's more concise than B) since the .get seems a bit treacherous. B is definitely the most explicit but mapping the Try cases to corresponding Future outcomes seems boring.
How would an experienced Scala programmer write this?
I think your initial version using try/catch is perfectly fine, because it's a wrapper around an existing SDK.
Alternatively, you can use the recover method on Future:
def findCustomer(userId: Long): Future[Option[Customer]] =
Future(Option(gateway.find(userId))).recover {
case e: NotFoundException => None
}
One option is to avoid chaining Try and Future. In a sense, a future is an asynchronous Try.
You could use Future[Customer] directly and consider NotFoundException as something to recover from rather than a None value. Normally, you would chain operation on the future itself, with no need to deal with the failure cases (by mapping it, etc). It all depends on how you are going to use it (how your logic branches when the future is completed). In other words, maybe it seems convoluted to you because it is, and you are forcing it to be by forcing the Future[Option[Customer]] return type.
The ability to do chain multiple operations and carry on with computing if and only if all if going all right is the nice Scala feature here (especially on for comprehensions, etc).
You might be looking for:
Future.fromTry(myTry)
So for your example you might do:
Future.fromTry {
Try(Some(gateway.find(userId))).recover {
case _: NotFoundException => None
}
}
To only catch the NotFoundException, as in your solution. The only problem here is that the method won't be executed asynchronously. If that is necessary, consider using Future.recover, as suggested by Ionut.
Another idiomatic option worth mentioning here is to use Either[F, S], where S is the type of the successful return, and F can hold the errors (which you might want to propagate). So you could use Either[ Exception, Option[String]] or Either[String, Option[String]] where the first String is an error message.
If you're ready to adopt some scalaz. disjunction from scalaz is very useful and natural in handling erronous scenarios. It's like scala Either but scalaz disjunction \/ is right biased. you'll have success value on the right and exception on left. wrapping your code block with \/.fromTryCatch returns exception on the left side of disjunction. right will always have success value. mapping over disjunction is easiser than Scala Either since disjunction is right biased and easily gives you value from right.
import scalaz.\/
private def findCustomer(userId: Long): Future[\/[Throwable,Option[Customer]] ]= future {
\/.fromTryCatch {
Some(gateway.find(userId))
}
}
Should a Scala API ideally throw exceptions or return a Try value? Is there an official guideline regarding this?
def doSomethingMayThrow(): A = ???
def doSomethingWontThrow(): Try[A] = ???
Never throw exceptions for recoverable errors.
Returning appropriate data structure representing a possible failure (a Future, a Try, an Either and so on) is always preferable than throwing exceptions in the wild. It will inform the caller about the possibility of a failure, and it will force them to manage it.
Exceptions should only be thrown for unrecoverable errors, such as hardware failures and similar.
Let's make an example:
def throwOnOdds(x: Int): Int =
if (x % 2 == 0) x / 2 else throw new Exception("foo")
val x = throwOnOdds(41) + 2 // compiles and explodes at runtime
now, let's make it better
def throwOnOdds(x: Int): Try[Int] =
if (x % 2 == 0) Success(x / 2) else Failure(new Exception("foo"))
val x = throwOnOdds(41) + 2 // doesn't compile
Not handling the failure leads to a compile-time error, which is way better than a runtime one. Here's how to handle it
throwOnOdds(41) match {
case Success(n) => // do something with n
case Failure(e) => // handle exception
}
See monadic datatypes. Using monadic datatypes is much more expressive and clear than throwing exceptions and would be the preferred way of declaratively handling all cases without unclear side effects.
http://en.wikipedia.org/wiki/Monad_(functional_programming)
The advantage of using a failure vs success and using map and flatMap to express the 'happy path' is that exceptions/failures become explicit in the chain.
Where you can tell if you call to doSomethingMayThrow might have a side effect (eg throwing an exception) it is very clear when you use a monadic datatype as a result.
It would help to look at a real world case. I'll use this as it is something i have worked on recently:
Consider a monadic future in a caching scenario - if the cache returns a result, you can process the result. If the cache does not return a result, then we can go to the actual service that we are trying to cache results from and we can express it very explicitly without any unclear implied side effects such as exception :
Here recoverWith is like flatMap on the error case (return a Future[Model] instead of the failure). recover is like map on the error case (return a model on the future instead of the failure). Then map takes whatever the resulting model is and processes it - all cases are clearly defined in the code so there is clarity of all cases and conditions in a single expression.
(userCacheActor ? GetUserModel(id="abc"))
.recoverWith(userServiceActor ? GetUserModel(id="abc"))
.recover(new ErrorModel(errorCode=100, body="service error")
.map(x: Response => createHttpResponseFromModel(x))
def createHttpResponseFromModel(x: Model) =>
x match {
case model: ErrorModel => ???
case model: UserModel => ???
}
Again, everything is expressively notated - what to do with the failure of the cache hit, what to do if the service can't respond in that scenario, what to do with the result model at the end of all of the processing in any case.
Often flatMap is talked about as the 'plumber' of the monad or 'plumber' of the happy path. flatMap allows you to take another Monad and return it. So you can 'try' multiple scenarios and write the happy path code collecting any errors at the end.
scala> Option("Something").flatMap(x => Option( x + " SomethingElse"))
.flatMap(x => None).getOrElse("encountered None somewhere")
res1: String = encountered None somewhere
scala> scala.util.Try("tried")
.flatMap(x => scala.util.Try( x + " triedSomethingElse"))
.flatMap(x => scala.util.Try{throw new Exception("Oops")})
.getOrElse("encountered exception")
res2: String = encountered exception
Does Scala have an equivelent to golangs defer?
from:
http://golang.org/doc/effective_go.html#defer
Go's defer statement schedules a function call (the deferred function) to be run immediately before the function executing the defer returns. It's an unusual but effective way to deal with situations such as resources that must be released regardless of which path a function takes to return. The canonical examples are unlocking a mutex or closing a file.
Scala does not offer defer by design, however you can create it yourself by wrapping
your function in another function, passing an object which keeps track of functions to call.
Example:
class DeferTracker() {
class LazyVal[A](val value:() => A)
private var l = List[LazyVal[Any]]()
def apply(f: => Any) = { l = new LazyVal(() => f) :: l }
def makeCalls() = l.foreach { x => x.value() }
}
def Deferrable[A](context: DeferTracker => A) = {
val dt = new DeferTracker()
val res = context(dt)
dt.makeCalls
res
}
In this example, Deferable would be the wrapping function which calls context and
returns it contents, giving it an object which tracks defer calls.
You can use this construct like this:
def dtest(x:Int) = println("dtest: " + x)
def someFunction(x:Int):Int = Deferrable { defer =>
defer(dtest(x))
println("before return")
defer(dtest(2*x))
x * 3
}
println(someFunction(3))
The output would be:
before return
dtest: 6
dtest: 3
3
I'm aware that this can be solved differently but it is really just an example that
Scala supports the concept of defer without too much fuss.
I can't think of a Scala specific way, but wouldn't this be equivalent (though not as pretty):
try {
// Do stuff
} finally {
// "defer"
}
No. Go has this construct precisely because it doesn't support exceptions and has no try...finally syntax.
Personally, I think it invites a maintenance nightmare; calls to defer can be buried anywhere in a function. Even where responsible coders put the defers right beside the thing to be cleaned up, I think it's less clear than a finally block and as for what it lets the messy coders do... at least finally blocks put all the clean-up in one place.
defer is the opposite of idiomatic Scala. Scala offers monadic ways to control program flow and defer magic does not contribute at all. Monads offer a functional improvement over try...finally which let you
Define your own error handling flow
Manipulate defined flows functionally
Make a function's anticipated errors part of its signature
defer has no place in this.