When I first read the internal version of Jed’s Exceptions are Bad™, I couldn’t find the fundamental differences between checked exceptions and returning sum types. I’ve read a few responses that also raise that question.

If you think about it, you could come up with a model that transformed checked-exceptions to Either types. A method like this:

[cc lang=’java’]public Integer mightNotWork(Integer x) throws MightNotWorkException
{
if (x > 100)
{
throw new MightNotWorkException();
}
return x – 1;
}[/cc]

Could easily be turned into a method like:

[cc lang=’java’]public Either mightNotWork(Integer x)
{
if (x > 100)
{
return left(new MightNotWorkException());
}
return right(x – 1);
}[/cc]

Very easy transformation. Now, exceptions from the caller side:

[cc lang=’java’]public Integer catchMightNotWork()
{
try
{
return mightNotWork(50) – 1;
}
catch (MightNotWorkException e)
{
return 0;
}
}[/cc]

And Either from the caller side:

[cc lang=’java’]public Integer catchMightNotWork()
{
Either x = mightNotWork(50);
return x.isRight() ? x.right() – 1 : 0;
}[/cc]

Another easy transformation.

Why is this interesting? They both can either: trap the outcome or pass it along. This is a form of composition. Seeing that they compose the same way really struck me. Composition is a big part of monads.

If you’re unsure about what a monad is or does, you should watch Tony Morris’ talk about them (slides here). You don’t have to have a complete grasp, just think of monads as an interface for values to compose together. The implication for both of the above solutions is that they have mathematically defined rules for composition.

There doesn’t seem to be much discussion online about exceptions being monads but I really liked the Exception page on the Haskell Wiki. Here’s the Haskell definition but with Java terms instead:

[cc lang=’haskell’]data JavaValue e a =
Success a
| Throw e

instance Monad (JavaValue e) where
return = Success
Throw l >>= _ = Throw l
Success r >>= k = k r

catch :: JavaValue e a -> (e -> JavaValue e a) -> JavaValue e a
catch (Throw l) h = h l
catch (Success r) _ = Success r[/cc]

For those who don’t Haskell: we create a datatype called “JavaValue” and it can either be a “Success” or a “Throw”. The “instance Monad” block gives a definition for how those values should compose. The “catch” function is very similar to a Java catch.

I really like that this raises a fact that not many are aware of: Java programmers use monads everyday.

Now this is very interesting but practically, composition is just one part of exceptions. I asked Jed and he made some really good points about the technical differences:

  • Java is the only language that considers exceptions to be part of the type signature, yet this is fundamentally at odds with the theory of type preservation (if a term is well-typed and is evaluated, the result is the same type)
  • Throwing an exception in Java is not referentially transparent; you can’t replace every given function call with “threw MightNotWorkException”
  • Java exceptions can’t have contravariance
  • Exceptions must subclass throwable, Either types can contain any references

The whole message behind Jed’s post is along the lines of “exceptions should only be used in exceptional circumstances”. This gives me a rule of thumb:

  • Use Either to pass data in non-problematic cases
  • Use exceptions when something has gone wrong

Fresh ideas, announcements, and inspiration for your team, delivered weekly.

Subscribe now

Fresh ideas, announcements, and inspiration for your team, delivered weekly.

Subscribe now