Moje zdjęcie
Software Craftsman's Blog by Marcin Pieciukiewicz
Java and Scala development

Sunday, September 15, 2013

Functional approach to Exception handling in Scala

Did you know that in functional programming world there is a criticism of throwing exceptions? It seems that it would break a functional programming principle that a function have to always return a value. I'm not sure that this approach is the best for all situations, but I can imagine some cases when it might be good. Especially because Scala dumped the idea of checked exceptions.

So what we could do if we would like not to throw the exception when the exceptional situation occurs? In example, when we receive a zero as denominator in division operator. In standard approach we could throw IllegalArgumentException, but what to do in a purely functional approach? We could return a Not-A-Number value or an Infinity value. But that would not be the best approach if this exceptional situation should be handled somehow. Also there is a risk that this value would be passed further in an application and that might cause a difficult to detect problem in other part of the code.

More reliable solution would be to return an info about the error. We could reuse the IllegalArgumentException, as it is an object that nicely describes the problem and, also, it can hold a stack trace, which can be useful for debugging. So let's look at the example code:
def divide(a:Double, b:Double) = {
  if (b == 0) {
    new IllegalArgumentException("Cannot divide by zero!")
  } else {
    a / b
That might work, but what type returns the divide function? In this case Scala compiler we'll choose Any as closest common ancestor. That means, a user of our function we'll have to check returned type and manually cast a result to a Double. You can imagine that this is inconvenient, and sometimes might cause ClassCastException when user won't predict correctly all possible types that might be returned.

Some literature suggests usage of Either[A,B] class from standard Scala's library. Basically this is an extension of an Option idea. Either object can hold a value in one of it's two fields: left and right. This can be leveraged to be useful in exception handling if we assume that we'll always put correct result in right field and error in left field. This way we could have more control over returned type, and we could handle an exception using pattern matching. I would recommend to get familiar with Either class as it can be useful in some situations, but I also think that it is not a best solution to handle exceptional situations. First, for my taste, it is too general and it requires a convention that must be known by every user. I would like to propose a different approach, inspired by Either class, but with more specific purpose.

My solution is based on a new Result class which would be a holder of a function result value, or an exception, if required. Here is it's definition:
abstract class Result[A, E <: Throwable] {
  def isSuccess: Boolean
  def isFailure: Boolean
  def get: A
  def getOrDefault(default: => A): A
  def error: E
As you can imagine this class can have two basic states implemented as two case classes, Success and Failure:
final case class Success[A, E <: Throwable](result: A) extends Result[A, E] {
  override def isSuccess = true
  override def isFailure = false
  override def get: A = result
  override def error: E = throw new IllegalAccessException("It's a success, not a failure")
  override def getOrDefault(default: => A): A = result

final case class Failure[A, E <: Throwable](err: E) extends Result[A, E] {
  override def isSuccess = false
  override def isFailure = true
  override def get: A = throw err
  override def error: E = err
  override def getOrDefault(default: => A): A = default
Those two are very simple implementation of abstract Result[A, E] class. Before we go into details of this implementation let's look how it can be used in our divide function:
class DivideByZeroException extends IllegalArgumentException("Cannot divide by zero")

def divide(a: Double, b: Double): Result[Double, DivideByZeroException] = {
  if (b == 0) {
    Failure(new DivideByZeroException)
  } else {
    Success(a / b)
I hope it doesn't require a lot of explanation. Our modified function is returning a Result[Double, DivideByZeroException] type which will be a Failure containing an exception if b is equal zero, or a Success containing the result of computation in other cases.
Let's look closer on a methods provided by Result class:
  • isSuccess and isFailure - those methods simply allow us to distinguish between Success and Failure objects
  • get - this methods returns a result value in the case of a Success object, or it throws the inner exception object in the case of an Failure object
  • error - this method returns an exception object that was contained inside Failure object, or it throws an IllegalAccessException in the case of a Success instance
  • getOrDefault(default: => A) - this method is similar to get method, so it returns a result value in the case of Success object, but in the case of Failure instead of throwing an exception it returns a value passed as default (if default is an expression it is evaluated only if needed)
This set of methods, and the fact that Success and Failure are case classes, provides us with a convenient way of handle results returned from functions. Let's look at some examples where function succeedes:
scala> divide(10, 2)
res = Success(5.0)

scala> divide(10, 2).get
res = 5.0

scala> divide(10, 2).isSuccess
res = true

scala> divide(10, 2).isFailure
res = false

scala> divide(10, 2).getOrDefault(27)
res = 5.0

scala> divide(10, 2).error
java.lang.IllegalAccessException: It's a success, not a failure  // IllegalAccessException was thrown
And now the case when function returns a Failure:
scala> divide(10, 0)
res = Failure(java.lang.IllegalArgumentException: Cannot divide by zero)

scala> divide(10, 0).get
DivideByZeroException: Cannot divide by zero  // DivideByZeroException was thrown

scala> divide(10, 0).isSuccess
res = false

scala> divide(10, 0).isFailure
res = true

scala> divide(10, 0).getOrDefault(27)
res = 27.0

scala> divide(10, 0).error
res = DivideByZeroException: Cannot divide by zero  // DivideByZeroException was returned, not thrown
Those were simple, method's use cases, here you can look how it is possible to handle exceptions now:
Simple if checking for success:
val divideResult = divide(10, 2)
if (divideResult.isSuccess) {
  println("Result of division is " + divideResult.get)
} else {
  println("You shouldn't divide by zero")
Do you remember the C times when negative number have meant an error?
val result = divide(10, 0).getOrDefault(-1)
And this is probably most convenient way of doing this, with a usage of pattern matching:
divide(20, 5) match {
  case Success(x) => println("Result of division is " + x)
  case Failure(err) => println("Something went wrong: " + err.getMessage)

This approach to exception handling is only a proposition how it could be done if we would like to limit the throwing of the exceptions. There are people that believe in clean functional approach to programming and I think that they should be listened and understood. For me, dilemma between throwing an exception or returning it reminds me discussion about checked vs unchecked exceptions, that still doesn't have a winner.

I think that presented approach could be used when an exceptional situation is part of a business, ie. when parsing user's input. In this case we have to provide a response for any data user provided, even this corrupted. On the other hand this approach shouldn't be used to handle exception caused by internal error in our software, ie. parsing a rest request from other part of our system. In this case there is probably nothing smart to do, other than to fail gracefully, so it is best to throw an exception that will be handled by our application server.

I'm sure that with proper care both approaches have the justification for existence, even in one application.

As Konrad mentioned, Scala 2.10 is equipped with scala.util.Try class, which works almost the same as my Result class. That's great news, you can give it a try with no cost o creating custom class, and if you would like, you can use it in production code already.