Idiomatic Error Handling in Scala


Error handling in Scala can just be written like Java. Put in a little bit of pattern matching magic and you are done. However, given a little use of Scala built-in terrific beauties it can be made much better. Let us have a look.

Let us look at a quick example

def sayHello(any: Any) = {
    any match {
      case x: String => "Hello"
      case _ => throw new Exception("Huh!")
    }
  }                      //> sayHello: (any: Any)String

  def letMeSayHello = {
    sayHello(12)
  }                     //> letMeSayHello: => String

  letMeSayHello         //> java.lang.Exception: Huh!
                    //| 	at SomeThing$$anonfun$main$1.sayHello$1(SomeThing.scala:11)

So we have a method called sayHello which misbehaves when you do not pass a string to it. If you call it without a string, it blows up and hence the letMeSayHello invocation blows up as well.

Ok, now traditionally we have been so used to try catch blocks that we put them around.

def sayHello(any: Any) = {
    any match {
      case x: String => "Hello"
      case _ => throw new Exception("Huh!")
    }
  }                    //> sayHello: (any: Any)String

  def letMeSayHello = {
    try {
      sayHello(12)
    } catch {
      case e: Exception => "It's Ok if you dont want to say hello"
    }
 }                    //> letMeSayHello: => String

  letMeSayHello       //> res0: String = It's Ok if you dont want to say hello

Ok, so far so good. So we can really write Java in Scala 😉

Now let us see a better way (Idiomatic way!) of handling this

Scala comes with something called a Try. 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. Instances of Try[T], are either an instance of scala.util.Success[T] or scala.util.Failure[T].

Interesting, let us see how our code changes now

import scala.util.Try

def sayHello(any: Any): Try[String] = {
    Try {
      any match {
        case x: String => "Hello"
        case _ => throw new Exception("Huh!")
      }
    }
  }                       //> sayHello: (any: Any)scala.util.Try[String]

  def letMeSayHello = {
    sayHello(12)
  }                       //> letMeSayHello: => scala.util.Try[String]

  letMeSayHello      

So, we put a Try block around out sayHello method code. Now the method, letMeSayHello does not need to do explicit error handling. It gets back either Success(“Hello”) or Failure(java.lang.Exception: Huh!)

In the above scenario, it would get Failure(java.lang.Exception: Huh!) and you would be able to extract the value with

 letMeSayHello.isSuccess   //> res0: Boolean = false

Now, there are various ways of dealing with this. You could pattern match on the boolean and take an action like

 val result = letMeSayHello  //> result  : scala.util.Try[String] = Failure(java.lang.Exception: Huh!)
 if (result.isSuccess) result.get else "who cares"//> res0: String = who cares

OR you could simply do a getOrElse

val result = letMeSayHello.getOrElse("who cares") //> result  : String = who cares
}

OR you could let the letMeSayHello method handle the success and failure

 def letMeSayHello = {
    sayHello(12) match {
      case Success(result) => result
      case Failure(result) => "who cares"
    }
  }                       //> letMeSayHello: => String

  letMeSayHello           //> res0: String = who cares

OR you could get even fancier ! I like this one. The awesome recover mechanism

def letMeSayHello = {
    sayHello(12) recover {
      case e: Exception => "who cares"
    }
  }                       //> letMeSayHello: => scala.util.Try[String]

  letMeSayHello.get       //> res0: String = who cares

The recover allows you to recover in case of failures with an alternate condition that you would want to execute which results in a success. Hence, in this case, we mentioned that either we would get a success by default or we would convert the error into a success scenario by writing a recover block so that we can confidently call letMeSayHello.get

You can find the gist here, on the Knoldus GitHub account. Have fun!

Advertisements

About Vikas Hazrati

Vikas is the Founding Partner @ Knoldus which is a group of software industry veterans who have joined hands to add value to the art of software development. Knoldus does niche Reactive and Big Data product development on Scala, Spark and Functional Java. Knoldus has a strong focus on software craftsmanship which ensures high-quality software development. It partners with the best in the industry like Lightbend (Scala Ecosystem), Databricks (Spark Ecosystem), Confluent (Kafka) and Datastax (Cassandra). To know more, send a mail to hello@knoldus.com or visit www.knoldus.com
This entry was posted in Scala and tagged , . Bookmark the permalink.

5 Responses to Idiomatic Error Handling in Scala

  1. pkinsky says:

    Sorry, but nothing about this is idiomatic scala. At a minimum, sayHello should be defined as sayHello(any: String) so that passing in the wrong type is a compile time error. Idiomatic Scala leverages the type system as much as possible such that run time errors like the one above are detected at compile time.

    • That is fair, you can replace the method to be str:String. The idioms in a language more specifically in Scala is not limited to using the type system. Use of a notable feature in a specific progamming language would constitute an idiom. In this scenario the way Try is used along with benefits that comes along with using it in for comprehensions, filters etc would constitue the Scala idiom. Keep tuned for further treatment of Try

  2. For something like that you should just make your method look like this: def sayHello(any: Any): Either[String, String] = …

    Mostly because throwing exceptions and then immediately catching them isn’t idiomatic Scala at all and you can easily pattern match on the Left and Right subtypes of Either just as much.

    • > Mostly because throwing exceptions and then immediately catching them isn’t idiomatic Scala at all

      🙂 Agreed. The intent here is not to show that you throw and catch exception immediately. Replace the {throw Exception} with any processing logic which might result in an exception

    • annoymous says:

      The problem I’ve had isn’t when your ONLY using scala, its when you couple it with exception loving java. That’s why this pattern was really helpful for me. Thanks OP!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s