Shantanu Kamath
Aug 29 · 5 min read

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?

The 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.


Try what?

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.


Fatality!

The 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 Success[A].

Now you get it!


Hey you!

Yes you!
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. .
But 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.
Mapping a 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 Failure[A].

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…


TLDR;

Just use Try. It’s good. Trust me, I’m an engineer.

Shantanu Kamath

Written by

Data Engineer | Visa Inc. https://www.shantanukamath.xyz/blog

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade