Why `scala.util.Try` is not mentioned in chapter "Handling errors without exceptions" of book "functional programming in Scala"? - scala

In the chapter "Handling errors without exceptions" of book "functional programming in Scala", the author gives:
The problem of throwing exceptions from the body of a function
Use Option if we don't care about the actual exception
Use Either if we care about the actual exception
But scala.util.Try is not mentioned. From my point of view, I think Try is very suitable when we care about the actual exception, why it's not mentioned? Is there any reason I have missed?

I'm neither of the authors of Functional Programming in Scala, but I can make a few guesses about why they don't mention Try.
Some people don't like the standard library's Try because they claim it violates the functor composition law. I personally think that this position is kind of silly, for the reasons Josh Suereth mentions in the comments of SI-6284, but the debate does highlight an important aspect of Try's design.
Try's map and flatMap are explicitly designed to work with functions that may throw exceptions. People from the FPiS school of thought (including me) would tend to suggest wrapping such functions (if you absolutely have to deal with them at all) in safe versions at a low level in your program, and then exposing an API that will never throw (non-fatal) exceptions.
Including Try in your API muddles up the layers in this model—you're guaranteeing that your API methods won't throw exceptions, but then you're handing people a type that's designed to be used with functions that throw exceptions.
That's only a complaint about the standard library's design and implementation of Try, though. It's easy enough to imagine a version of Try with different semantics, where the map and flatMap methods didn't catch exceptions, and there would still be good reasons to avoid this "improved" version of Try whenever possible.
One of these reasons is that using Either[MyExceptionType, A] instead of Try[A] makes it possible to get more mileage out of the compiler's exhaustivity checking. Suppose I'm using the following simple ADT for errors in my application:
sealed class FooAppError(message: String) extends Exception(message)
case class InvalidInput(message: String) extends FooAppError(message)
case class MissingField(fieldName: String) extends FooAppError(
s"$fieldName field is missing"
)
Now I'm trying to decide whether a method that can only fail in one of these two ways should return Either[FooAppError, A] or Try[A]. Choosing Try[A] means we're throwing away information that's potentially useful both to human users and to the compiler. Suppose I write a method like this:
def doSomething(result: Either[FooAppError, String]) = result match {
case Right(x) => x
case Left(MissingField(_)) => "bad"
}
I'll get a nice compile-time warning telling me that the match is not exhaustive. If I add a case for the missing error, the warning goes away.
If I had used Try[String] instead, I'd also get exhaustivity checking, but the only way to get rid of the warning would be to have a catch-all case—it's just not possible to enumerate all Throwables in the pattern match.
Sometimes we actually can't conveniently limit the kinds of ways an operation can fail to our own failure type (like FooAppError above), and in these cases we can always use Either[Throwable, A]. Scalaz's Task, for example, is essentially a wrapper for Future[Throwable \/ A]. The difference is that Either (or \/) supports this kind of signature, while Try requires it. And it's not always what you want, for reasons like useful exhaustivity checking.

Related

What's the recommended way to deal with errors in Scala?

Let's say that I have a method addUser that adds a user to database. When called, the method might:
succeed
fail, because the input was invalid (i. e. the user name already exists)
fail, because the database crashed or whatever
The method would probably consist of a single database API call that would in case of failure throw an exception. If it was in plain Java, I'd probably catch the exception inside the method and examine the reason. If it fell in the second category (invalid input), I would throw a custom checked exception explaining the reason (for example UserAlreadyExistsException). In case of the second category, I'd just re-throw the original exception.
I know that there are strong opinions in Java about error handling so there might be people disagreeing with this approach but I'd like to focus on Scala now.
The advantage of the described approach is that when I call addUser I can choose to catch UserAlreadyExistsException and deal with it (because it's appropriate for my current level of abstraction) but at the same time I can choose to completely ignore any other low-level database exception that might be thrown and let other layers deal with it.
Now, how do I achieve the same thing in Scala? Or what would be the right Scala approach? Obviously, exceptions would work in Scala exactly the same way but I came across opinions that there are better and more suitable ways.
As far as I know, I could go either with Option, Either or Try. Neither of those, however, seem as elegant as good old exceptions.
For example, dealing with the Try result would look like this (borrowed from similar question):
addUser(user) match {
case Success(user) => Ok(user)
case Failure(t: PSQLException) if(e.getSQLState == "23505") => InternalServerError("Some sort of unique key violation..")
case Failure(t: PSQLException) => InternalServerError("Some sort of psql error..")
case Failure(_) => InternalServerError("Something else happened.. it was bad..")
}
Those last two lines are exactly something I'd like to avoid because I'd have to add them anywhere I make a database query (and counting on MatchError doesn't seem like a good idea).
Also dealing with multiple error sources seems a bit cumbersome:
(for {
u1 <- addUser(user1)
u2 <- addUser(user2)
u3 <- addUser(user3)
} yield {
(u1, u2, u3)
}) match {
case Success((u1, u2, u3)) => Ok(...)
case Failure(...) => ...
}
How is that better than:
try {
u1 = addUser(user1)
u2 = addUser(user2)
u3 = addUser(user3)
Ok(...)
} catch {
case (e: UserAlreadyExistsException) => ...
}
Has the former approach any advantages that I'm not aware of?
From what I understood, Try is very useful when passing exceptions between different threads but as long as I'm working within a single thread, it doesn't make much sense.
I'd like to hear some arguments and recommendations about this.
Much of this topic is of course a matter of opinion. Still, there are some concrete points that can be made:
You are correct to observe that Option, Either and Try are quite generic; the names do not provide much documentation. Therefore, you could consider a custom sealed trait:
sealed trait UserAddResult
case object UserAlreadyExists extends UserAddResult
case class UserSuccessfullyAdded(user: User) extends UserAddResult
This is functionally equivalent to an Option[User], with the added benefit of documentation.
Exceptions in Scala are always unchecked. Therefore, you would use them in the same cases you use unchecked exceptions in Java, and not for the cases where you would use checked exceptions.
There are monadic error handling mechanisms such as Try, scalaz's Validation, or the monadic projections of Either.
The primary purpose of these monadic tools is to be used by the caller to organize and handle several exceptions together. Therefore, there is not much benefit, either in terms of documentation or behavior, to having your method return these types. Any caller who wants to use Try or Validation can convert your method's return type to their desired monadic form.
As you can maybe guess from the way I phrased these points, I favor defining custom sealed traits, as this provides the best self-documenting code. But, this is a matter of taste.

What is the difference between Try and Either?

According to the documentation:
The Try type represents a computation that may either result in an
exception, or return a successfully computed value. It's similar to,
but semantically different from the scala.util.Either type.
The docs do not go into further detail as to what the semantic difference is. Both seem to be able to communicate successes and failures. Why would you use one over the other?
I covered the relationship between Try, Either, and Option in this answer. The highlights from there regarding the relationship between Try and Either are summarized below:
Try[A] is isomorphic to Either[Throwable, A]. In other words you can treat a Try as an Either with a left type of Throwable, and you can treat any Either that has a left type of Throwable as a Try. It is conventional to use Left for failures and Right for successes.
Of course, you can also use Either more broadly, not only in situations with missing or exceptional values. There are other situations where Either can help express the semantics of a simple union type (where value is one of two types).
Semantically, you might use Try to indicate that the operation might fail. You might similarly use Either in such a situation, especially if your "error" type is something other than Throwable (e.g. Either[ErrorType, SuccessType]). And then you might also use Either when you are operating over a union type (e.g. Either[PossibleType1, PossibleType2]).
Since Scala 2.12, the standard library does include the conversions from Either to Try or from Try to Either. For earlier versions, it is pretty simple to enrich Try, and Either as needed:
object TryEitherConversions {
implicit class EitherToTry[L <: Throwable, R](val e: Either[L, R]) extends AnyVal {
def toTry: Try[R] = e.fold(Failure(_), Success(_))
}
implicit class TryToEither[T](val t: Try[T]) extends AnyVal {
def toEither: Either[Throwable, T] =
t.map(Right(_)).recover(Left(_)).get
}
}
This would allow you to do:
import TryEitherConversions._
//Try to Either
Try(1).toEither //Either[Throwable, Int] = Right(1)
Try("foo".toInt).toEither //Either[Throwable, Int] = Left(java.lang.NumberFormatException)
//Either to Try
Right[Throwable, Int](1).toTry //Success(1)
Left[Throwable, Int](new Exception).toTry //Failure(java.lang.Exception)
To narrowly answer your question: "What's the semantic difference":
This probably refers to flatMap and map, which are non-existent in Either and either propagate failure or map the success value in Try. This allows, for instance, chaining like
for {
a <- Try {something}
b <- Try {somethingElse(a)}
c <- Try {theOtherThing(b)}
} yield c
which does just what you'd hope - returns a Try containing either the first exception, or the result.
Try has lots of other useful methods, and of course its companion apply method, that make it very convenient for its intended use - exception handling.
If you really want to be overwhelmed, there are two other classes out there which may be of interest for this kind of application. Scalaz has a class called "\/" (formerly known as Prince), pronounced "Either", which is mostly like Either, but flatMap and map work on the Right value. Similarly, and not, Scalactic has an "Or" which is also similar to Either, but flatMap and map work on the Left value.
I don't recommend Scalaz for beginners.
Either does not imply success and failure, it is just a container for either an A or a B. It is common to use it to represent successes and failures, the convention being to put the failure on the left side, and the success on the right.
A Try can be seen as an Either with the left-side type set to Throwable. Try[A] would be equivalent to Either[Throwable, A].
Use Try to clearly identify a potential failure in the computation, the failure being represented by an exception. If you want to represent the failure with a different type (like a String, or a set of case classes extending a sealed trait for example) use Either.
Either is more general, since it simply represents disjoint unions of types.
In particular, it can represent a union of valid return values of some type X and Exception. However, it does not attempt to catch any exceptions on its own. You have to add try-catch blocks around dangerous code, and then make sure that each branch returns an appropriate subclass of Either (usually: Left for errors, Right for successful computations).
Try[X] can be thought of as Either[Exception, X], but it also catches Exceptions on its own.
Either[X, Y] usage is more general. As its name say it can represent either an object of X type or of Y.
Try[X] has only one type and it might be either a Success[X] or a Failure (which contains a Throwable).
At some point you might see Try[X] as an Either[Throwable,X]
What is nice about Try[X] is that you can chain futher operations to it, if it is really a Success they will execute, if it was a Failure they won't
val connection = Try(factory.open())
val data = connection.flatMap(conn => Try(conn.readData()))
//At some point you can do
data matches {
Success(data) => print data
Failure(throwable) => log error
}
Of course, you can always oneline this like
Try(factory.open()).flatMap(conn => Try(conn.readData()) matches {
Success(data) => print data
Failure(throwable) => log error
}
As already have been mentioned, Either is more general, so it might not only wrap error/successful result, but also can be used as an alternative to Option, for branching the code path.
For abstracting the effect of an error, only for this purpose, I identified the following differences:
Either can be used to specify a description of the error, which can be shown to the client. Try - wraps an exception with a stack trace, less descriptive, less client oriented, more for internal usage.
Either allows us to specify error type, with existing monoid for this type. As a result, it allows us to combine errors (usually via applicative effects). Try abstraction with its exception, has no monoid defined. With Try we must spent more effort to extract error and handle it.
Based on it, here is my best practices:
When I want to abstract effect of error, I always use Either as the first choice, with List/Vector/NonEmptyList as error type.
Try is used only, when you invoke code, written in OOP. Good candidates for Try are methods, that might throw an exception, or methods, that sends request to external systems (rest/soap/database requests in case the methods return a raw result, not wrapped into FP abstractions, like Future, for instance.

Scala error handling: Try or Either?

Given a method in UserService: update, what's the best way to handle errors/exceptions here?
Option A:
def update(...): Try[User]
In this way, I need to define my custom exceptions and throw them in the function body when needed. Most of these exceptions are business errors (e.g. user_id cannot be changed, etc). The point here is no matter what exception(s) are thrown (business error, network exception, DB IO exception, etc), treat them the same way and just return a Failure(err) - let the upper layer handle them.
Option B:
def update(...): Either[Error, User]
This is the exception-free way. In the function body it catches all possible exceptions and turns them into Error, and for business errors just return Left[Error].
Using Try seems to be a more natural way to me as I want to handle errors. Either is a more generic thing - Either[Error, T] is just one special case and I think Try is invented for this special case. But I also read that we should avoid using exceptions for error handling...
So, which solution is better, and why?
There's no silver bullet.
As you noted already, Try is simply a more specialized version of Either, where the Left type is fixed to Throwable.
Try might be a good fit if you need to materialize exceptions thrown by external (perhaps java) libraries, as its constructor automatically catches them.
Another advantage of Try is that it has map and flatMap, so you can use it directly in for-comprehensions, whereas with Either you would have to explicitly project on the right case.
Anyway, there's plenty of alternative implementations with a "right-bias", and probably the scalaz \/ type is the most popular one.
That being said, I typically use \/ or the almost equivalent Validation (both from scalaz), as I like having the ability of returning errors that do not extend Throwable.
It also allows for more precise error types, which is a huge win.

Why is there an Option.get method

Why is the method get defined in Option and not in Some?
One could apply pattern matching or use foreach, map, flatMap, getOrElse which is preferred anyway without the danger of runtime exceptions if None.get is called.
Are there really cases where the get method is so much convinent that it justifies this? Using the get method reminds me to Java where "I don't have to check for null because I know the var is set" and then see a NullPointerException.
Option.get is occasionally useful when you know, by reasoning that isn't captured by the type system, that the value you have is not None. However, you should reach for it only when you've tried:
Arranging for this knowledge to be expressed by your types.
Using the Option processing methods mentioned (flatMap, getOrElse etc), and none of them fit elegantly.
It's also convenient for throwaway / interactive code (REPL, worksheets etc).
Foreword
Scala was created with compatibility for the JVM as a target.
So it's pretty natural that Exceptions and try/catch should be considered as part of the language, at least for java interoperability.
With this premise in mind, now to the point of including interfaces that can throw errors in algebraic data types (or case classes if you prefer).
To the Question
Assume we encapsulate the get method (or head for List) only in Some instance.
This implies that we're forced to pattern match on the Option every time we want to extract the value. It wouldn't look pretty neat, but it's still a possibility.
We could getOrElse everywhere but this means that I can't signal a failure through the error stack if using imperative style (which is not forbidden in scala, the last time I checked).
My point here is that getOrElse and headOption are available to enforce a functional style when desired, but get and head are good alternatives if imperative is a choice fit to the problem or the programmer's preference.
There is no good reason for it. Martin Odersky added it in this commit in 2007, so I guess we'd need to ask him his motivations. The earlier version had getOrElse semantics.
If you examine the commit provided. It's kind of obvious why and
when it is used. The get is used to unbox when you are sure there is Something in the
Option. It would also serve to be an inheritable method where None.get Throws an exception and Some.get unboxes the contents.
In some cases, when your Option turns out to be a None, there is no recourse and you want to throw an exception. So, instead of writing
myOption match {
case Some(value) => // use value
case None => throw new RuntimeException("I really needed that value")
}
you can simply write
myOption.get // might throw an exception
It also makes Option much nicer to use from Java, in conjunction with isDefined:
if (myOption.isDefined()) process(myOption.get());
else // it's a None!

Throwing exceptions in Scala, what is the "official rule"

I'm following the Scala course on Coursera.
I've started to read the Scala book of Odersky as well.
What I often hear is that it's not a good idea to throw exceptions in functional languages, because it breaks the control flow and we usually return an Either with the Failure or Success.
It seems also that Scala 2.10 will provide the Try which goes in that direction.
But in the book and the course, Martin Odersky doesn't seem to say (at least for now) that exceptions are bad, and he uses them a lot.
I also noticed the methods assert / require...
Finally I'm a bit confused because I'd like to follow the best practices but they are not clear and the language seems to go in both directions...
Can someone explain me what i should use in which case?
The basic guideline is to use exceptions for something really exceptional**. For an "ordinary" failure, it's far better to use Option or Either. If you are interfacing with Java where exceptions are thrown when someone sneezes the wrong way, you can use Try to keep yourself safe.
Let's take some examples.
Suppose you have a method that fetches something from a map. What could go wrong? Well, something dramatic and dangerous like a segfault* stack overflow, or something expected like the element isn't found. You'd let the segfault stack overflow throw an exception, but if you merely don't find an element, why not return an Option[V] instead of the value or an exception (or null)?
Now suppose you're writing a program where the user is supposed to enter a filename. Now, if you're not just going to instantly bail on the program when something goes wrong, an Either is the way to go:
def main(args: Array[String]) {
val f = {
if (args.length < 1) Left("No filename given")
else {
val file = new File(args(0))
if (!file.exists) Left("File does not exist: "+args(0))
else Right(file)
}
}
// ...
}
Now suppose you want to parse an string with space-delimited numbers.
val numbers = "1 2 3 fish 5 6" // Uh-oh
// numbers.split(" ").map(_.toInt) <- will throw exception!
val tried = numbers.split(" ").map(s => Try(s.toInt)) // Caught it!
val good = tried.collect{ case Success(n) => n }
So you have three ways (at least) to deal with different types of failure: Option for it worked / didn't, in cases where not working is expected behavior, not a shocking and alarming failure; Either for when things can work or not (or, really, any case where you have two mutually exclusive options) and you want to save some information about what went wrong; and Try when you don't want the whole headache of exception handling yourself, but still need to interface with code that is exception-happy.
Incidentally, exceptions make for good examples--so you'll find them more often in a textbook or learning material than elsewhere, I think: textbook examples are very often incomplete, which means that serious problems that normally would be prevented by careful design ought instead be flagged by throwing an exception.
*Edit: Segfaults crash the JVM and should never happen regardless of the bytecode; even an exception won't help you then. I meant stack overflow.
**Edit: Exceptions (without a stack trace) are also used for control flow in Scala--they're actually quite an efficient mechanism, and they enable things like library-defined break statements and a return that returns from your method even though the control has actually passed into one or more closures. Mostly, you shouldn't worry about this yourself, except to realize that catching all Throwables is not such a super idea since you might catch one of these control flow exceptions by mistake.
So this is one of those places where Scala specifically trades off functional purity for ease-of-transition-from/interoperability-with legacy languages and environments, specifically Java. Functional purity is broken by exceptions, as they break referential integrity and make it impossible to reason equationally. (Of course, non-terminating recursions do the same, but few languages are willing to enforce the restrictions that would make those impossible.) To keep functional purity, you use Option/Maybe/Either/Try/Validation, all of which encode success or failure as a referentially-transparent type, and use the various higher-order functions they provide or the underlying languages special monad syntax to make things clearer. Or, in Scala, you can simply decide to ditch functional purity, knowing that it might make things easier in the short term but more difficult in the long. This is similar to using "null" in Scala, or mutable collections, or local "var"s. Mildly shameful, and don't do to much of it, but everyone's under deadline.