Written originally at: The — I didn’t know that — blog
Why Try? — Scala Error Handling
Writing an application that performs smoothly when everything goes as expected solves only half of the problem. But making sure that the application behaves properly when encountering unexpected conditions is where it really gets challenging. You could say that having a good understanding of the domain helps you better address the other half, but only if your language helps you support it. TLDR; at the end.
Throw that exception!
Imagine a developer trying to begin work at the start of the day.
Due to an overwhelming amount of bugs introduced by sleepy developers, the company has mandated the following check on all laptops and their users.
Now, frustrated developers need to be able to handle such an exception.
It’s the only way to access their coveted Preferred IDE.
Luckily, the developers were aware of Scala’s (Java’s) generic try/catch and groggily wrote the exception handling.
Voila! The developer is now awake and ready to code.
And just in case, the coffee did not work..
Well if this works, why does scala.util.Try exist?
try/catch implementation in Scala is exactly similar to java which makesit is not in sync with the unique demands of Scala. For this purpose, there was a need to create
scala.util.Try which is a Monad.
Now let’s discuss the need for
Try in detail and how it provides an alternative experience. I will highlight features that are unique to Try and how it can be essential in the certain use-cases of Scala.
At the end of this, I would like the take away to be that Scala developers should consider using
Try instead of
try/catch in most cases.
The Try Monad represents a computation that may either result in an exception, or return a successfully computed value.
If you have an instance of type
Try[A], as successful computation would result in
Success[A] where the value of A would be the ouput of the computation. An unsuccessful computation, would result in
Failure[A] which actually wraps a
Throwable which is any kind of NonFatal exception. It is important to note that, Try only wraps NonFatal exceptions. Any Fatal exceptions such as those mentioned earlier, are unhandled and cause the program to fail irrevocably, as it rightly should. The Try type has a number of useful methods that help the developer to handle the situation as seen fit.
Lets look at an example.
try/catch - as in java and scala - allows for an match all case which catches all exceptions and errors. These include Fatal Exceptions such as :
OutOfMemoryError, InterruptedException, StackOverFlowExceptions etc. You may think of an Error as a Fatal Exception . It usually never makes sense to even try and recover from this because there is hardly anything you can do to handle these within your application. Catching of such conditions, is considered a bad practice.
Try on the other hand, only allows you to handle NonFatal exceptions, while Fatal exception rightfully cause the program to crash.
Using Try prevents unknowingly these situations. It internally check if the Throwable is Fatal or NonFatal.
You don’t get it.
Now the problem with
try/catch and concurrency. When using
Future, the exception may be thrown on a different thread than the caller, and so can’t be returned through the stack. You never really get the exception.
try/catch have no capabilities to encapsulates this exception and carry it forward to the caller.
If only there was a way to return an exception on failure and the result on success. Oh wait!
With Try, an exception on a separate thread can be wrapped up as
Failure[A] and sent up the stack to the caller and hence at least notify the existence of an exception and the stack trace. The callback method basically has a return type of
Try[A] and provides successful results in the form of
Now you get it!
Do you keep referring to code documentation and sort through javadocs to check if a particular function throws an exception?
Do you forget to check and assume that no exception is thrown by the function call?
Do you even Error Handle bruhh?
Traditionally a function either returns the result or throws an exception. But you will never know if it can or will throw an exception. Well not until its too late anyway. There was no proper way to alert the caller that it has to handle the possible exception. But by simply setting the return type of a function as a
Try, you force the developer to handle the possible exceptions. You start the error handling process. There by adding to the essence of graceful error handling.
The good, the ugly and the bad.
(Subjective to the kind of functional programming follower you are) Besides the issues mentioned above, the
try/catch code all over the code base adds a lot of verbosity and makes the code look ugly. .
Try adds to the logic of only two possible outcomes. As done in monads such as Either and Option. They provide and adapt the general syntactic sugar of the code.
Now, having said all this ‘try/catch’ is not bad at all.
Try itself implements
try/catch within its source code, for the sole reason of making the life of a developer better. But one can’t help but think about the additional overhead it brings in when working with Big Data. And yes, this might be a valid concern and generally comes down to cost vs benefit analysis. But on a side note, if you were wondering:
Try has no finally and it doesn’t really need it.
The Magician’s code.
Try enables a new set of magic within scala. Using
Try provides you with the ability to use functions such as map, flatMap, filter etc. which are available in collections.
Try[A] which has a
Success[A] to a
Try[B] results in a Success[B]. If map is performed on
Failure[A], the resulting
Try[B] will be a
Failure[B] but, containing the same exception as the
Examples of composing on these exceptions by using try is:
These code blocks will execute until each operation results in a
Success[A] and would return a
Failure[A] when the corresponding operation returning an
A fails. With Try, you can also enjoy the syntactic sugar of for comprehensions.
That’s all I have from my side folks…
Just use Try. It’s good. Trust me, I’m an engineer.