Functional Error Handling (FEH)

Introduction

In Scala, the correct solution to handling potential errors is to use Scala’s error-handling data types. In short, this means that a function that can fail should return one of the Option, Try, or Either types:

def wc(f: File): Option[?]
def wc(f: File): Try[?]
def wc(f: File): Either[?]

The basic idea is that you return an error-handling data type to account for the possibility that an error may occur in this function.

These types are wrappers

Error-handling types are basically wrappers, and inside their wrapper they contain one of two possibilities:

  • The function succeeded, and you can access its success value
  • The function failed, and you can access its error value

So it’s like you’re getting a container back from a function:

┌───────────────────────────────────────┐
│                                       │
│   Success Value  OR  Failure Value    │
│                  --                   │
└───────────────────────────────────────┘

As shown, when you get the container back from the function, it will contain either a Success Value or a Failure Value — but not both.

A great thing about this approach is that unlike exceptions, they don’t short-circuit your code: you’re just working with another data type. You treat this result as a value, and you continue writing your code as algebra. You’ll see what this means shortly.

The Option, Try, and Either error-handling data types take slightly different approaches, but that’s the essence of them.

So let’s see how they work.

The three error-handling types

As mentioned, Scala’s three error-handling types are named Option, Try, and Either. Thinking in OOP for a moment, each of these are parent data types, and they each have two sub-types.

For these three values, these are the parent types and their two sub-types:

  • Option, Some, and None
  • Try, Success, and Failure
  • Either, Right, and Left

Their class hierarchies are basic OOP, and look like this:

      ┌──────────┐
      │  Option  │
      └────┬─────┘
           │           
     ┌─────┴──────┐    
     │            │    
┌────┴───┐   ┌────┴───┐
│  Some  │   │  None  │
└────────┘   └────────┘

this:

        ┌─────┐
        │ Try │
        └──┬──┘
           │            
     ┌─────┴──────┐     
     │            │     
┌────┴────┐  ┌────┴────┐
│ Success │  │ Failure │
└─────────┘  └─────────┘

and this:

       ┌──────────┐ 
       │  Either  │
       └────┬─────┘
            │            
     ┌──────┴──────┐     
     │             │     
┌────┴───┐    ┌────┴────┐
│  Left  │    │  Right  │
└────────┘    └─────────┘

If your background is Java, you can think of Option, Try, and Either as being interfaces, and their sub-types are implementations of their interface.

In the following lessons we’ll look at what this means, and how these types work.