Lazy Error Handling in Java, Part 2: Thrower is a Monad

In Part 1, we talked about the Thrower interface, and how we could use it to separate error handling from the code that produces those errors. We also saw how we could exploit generics to create a functor that can promote an existing function to a function that can handle and throw errors.

In this post, we’ll see that the greatest benefit of Thrower is the ability to compose and sequence computations; even computations that may fail, all the while staying type-safe. We’ll introduce some new functions which allow us to perform a kind of Thrower arithmetic that in turn will let us manipulate values tucked away in Throwers, without ever having to extract from them, and without any exceptions being thrown or caught.

The ingredients we need are exactly the ingredients needed for a monad. That is: A type construction, a unit function, and a binding operation. The first ingredient, type construction, we already have. The Thrower interface is generic, so it lets us create a type Thrower<A, E> for any type A, given some Throwable type E.

The unit function is simple enough. It just creates a new Thrower that completely preserves the value that we put in it:

  
  public static <A, E extends Throwable> Thrower<A, E> unit(final A a) {
    return new Thrower<A, E>() {
      public A extract() {
        return a;
      }
    };
  }

The final ingredient for our Thrower monad is the bind function. It takes a Thrower and feeds its result to a function that returns another Thrower:

  
  public static <A, B, E extends Throwable> Thrower<B, E>
  bind(final Thrower<A, E> a, final F<A, Thrower<B, E>> f) {
    return new Thrower<B, E>() {
      public B extract() throws E {
        return f.f(a.extract()).extract();
      }
    };
  }

Check what this actually does. It creates a new Thrower, whose extract() method calls the extract() method on the first Thrower and applies the function f to the result. Nothing actually happens when we call bind, except that a new future call to the provided function is created. So we’re applying f to the contents of the Thrower a, but not suffering any consequences until later, whenever we decide to call extract() on the result of bind.

Note that we can only compose, in this manner, Throwers that throw the same Throwable type. To combine Throwers of different kinds of exceptions, you would need to return a Thrower<Thrower<A,E1>,E2>>, or something like a Thrower2<B,E1,E2> which can throw either E1 or E2. You cannot create a new generic Throwable like MyException<E1, E2> as the disjoint union of two Throwables, since subclasses of Throwable are not allowed to be generic due to Java’s runtime type erasure. Normally, I don’t care about the types of exceptions to that level of detail anyway, so if I need to work with different species of them, I just use the Exception type. That’s exactly what we’ll do in the example further down.

Now, notice the second argument to bind:

          
  final F<A, Thrower<B, E>> f

This is a pretty useful kind of thing. It’s a function that takes an A and either returns a B or throws an E. So it’s kind of like a Thrower that takes an argument. It’s actually a Kleisli Arrow for the Thrower monad. This is something we’ll need often, so let’s make them easy for ourselves to create:

  
  public abstract class Partial<A, B, E extends Throwable> implements F<A, Thrower<B, E>> {

  protected abstract B run(final A a) throws E;

    public final Thrower<B, E> f(final A a) {
      final Partial<A, B, E> self = this;
      return new Thrower<B, E>() {
        public B extract() throws E {
          return self.run(a);
        }
      };
    }
  }
   

It’s called Partial because it models a partial function, a function whose result is undefined for some values (i.e. it might throw an exception instead of returning a value). We’ve abstracted away all the Thrower stuff (it’s always going to work the same anyway), so concrete subclasses will only have to override the run method and do what a partial function would: turn an A into a B or throw an E.

It might seem that this has taken us full circle, that this was all an exercise in futility if we’re back to just writing methods that throw exceptions. But no, what we have so far actually gives us a lot of power under the hood.

For the token contrived example, let’s say that you have an abstract class which models an action to get some object from the network given a URLConnection, possibly throwing a network error:

    
  public abstract class NetTalker<A> extends Partial<URLConnection, A, Exception> {}

Even though this class has no body, its intent is very clear. Users of our API will just have to to override run to do something useful with a connection. But NetTalkers just use connections; the construction of URLConnections will be implementation-specific. We’ll use another class:

  
  public abstract class URLConnector extends Partial<URL, URLConnection, Exception> {}

Where concrete subclasses create different concrete URLConnections. To get an A from a URL, given some URLConnector c (that knows how to make HttpURLConnections) and some NetTalker n, we can do the following:

          
  Thrower<A, Exception> t = bind(c.f("http://foo.bar"), n);

Again, this doesn’t give you the object of type A, it merely gives you a Thrower which either returns the A or throws an exception. It’s lazy. You can take t and bind it to a Partial that takes an A and, say, writes it to a file, again returning a lazy Thrower. Then, when something calls extract() on it, the whole enchilada of operations will be executed in one go.

Or, if you have a whole list of Throwers, you could turn them into a Thrower that returns a list:

  

  public static <A, E extends Throwable> Thrower<List<A>, E> sequence(final List<Thrower<A, E>> ts)
  {
    return ts.foldRight(Throwers.<List<A>, E> unit(List.<A>nil()),
      Throwers.<A, List<A>, List<A>, E> liftM2(List.<A> cons()));
  }

The above collapses an entire list of throwers into a single thrower that returns all their results in one list. Here, List is a fj.data.List from Functional Java, not java.util.List, although this can be made to work quite easily with the Java Collections Framework by defining nil(), cons(), and foldRight(). liftM2 is almost exactly like fmap from Part 1, except that it lifts functions of arity-2.

We’ve only had a slight taste of what we can do with monads, even in Java, and there are relationships between fmap, bind, and unit that are worth understanding in detail. As you can see, it’s a powerful abstraction that can be applied to a wide variety of problems. It doesn’t stop with Throwers. Notice that NetTalker is also a generic type, with a single type parameter. Yes, it too is a functor. It too can be a monad, and can be composed as we did with Throwers. In fact, here’s fmap for NetTalker:

 
  public static <A,B> F<NetTalker<A>, NetTalker<B>>
    fmap(final F<A,B> f) {
      return new F<NetTalker<A>, NetTalker<B>>() {
        public NetTalker<B> f(final NetTalker<A> a) {
          return new NetTalker<B>() {
            public B run(URLConnection u) throws Exception {
              return f.f(a.f(u));
            }
          };
        }
      };
    }

I wonder what other types are monadic.

Unfortunately, you’ll find that you can’t write a generic Monad class in Java. Poor Java’s type system is not sophisticated enough to understand higher-kinded types, nor would that be sane without type inference in the compiler, which Java also lacks. You will have to write bind and unit for every kind of monad that you need, as well as all operations based on them (fmap, sequence, etc.), or dispense with the type system (in which case you may as well be writing Ruby), or switch to Scala.

I hope you enjoyed this little journey through monads and exceptions in Java. In Part 3 of this series, we will look at how we can remove try, catch, and throws entirely from our code, in favor of unit, bind, fmap, and join.

11 thoughts on “Lazy Error Handling in Java, Part 2: Thrower is a Monad

  1. Apocalisp: Because Sam doesn’t know what a monad is, or why one might want to model computation in the type system.

  2. off topic: i know there are various reasons for using ‘final’ in java. you seem to use it a lot more than most folks. what are your reasons for it?

    in particular, in the examples above when you make the return value + parameters to a function ‘final’, why are you doing that?

    (the general reasons for using ‘final’ i know of are: it cuts down the chances of think-o bugs; it can allow more optimizations to happen; it can be useful for ‘security’ of a fashion. those general statements map down to more concrete things depending on where ‘final’ is actually used.)

    thanks.

  3. Raoul,

    The final keyword is used for several reasons, like you said.

    1. To help enforce referential transparency by disallowing assignment to pseudovariables (all fields are final).
    2. To avoid what you call “think-o” bugs where you assign to a variable or argument (all method parameters and local variables final).
    3. To improve encapsulation by disallowing inheritance (classes are final).
    4. To facilitate closure. An inner scope (anonymous instance, for example) may not close over a variable that isn’t final.

  4. This is a very interesting series of posts! Alas, I encounter difficulties in expanding your example of the NetTalker into a chain of three monads. Could you please illustrate how to bind these three: UrlConnector –> NetTalker — > ABProcessor (where ABProcessor is some Partial that takes an A and returns a Thrower) ?
    Thanks and have a nice day,
    Marco Faustinelli

    • Marco,

      You want Kleisli composition. It would be implemented something like this:

      public <A,B,C,E> compose(final Partial<A,B,E> f, final Partial<B,C,E> g) {
        return new Partial<A> {
          public C run(A a) throws E {
            bind(f.f(a), g);
          }
        };
      }
      

      Now this is easy. If you have UrlConnector c, NetTalker n, and ABProcessor p, and some url:

       compose(c, compose(n, p)).f(url)
      

      That will give you a Thrower<B> where B is the result type of p. You probably want to add composition as a method on Partial, so that you can do it infix:

       c.compose(n).compose(p).f(url)
      
      • Thanks for the fast reply, Runar.
        This is somewhat a surprise to me: I understood it was bind the glue to form chains of monads. I saw somewhere the Haskell syntax a >>= b >>= c, I read the operator >>= is called “bind” and I imagined your bind was the same thing. Possibly I am not grasping the matter as a whole. [I don’t know Haskell, but I want to understand this matter using good old Java.]
        Again, a nice day to you
        Marco

      • Marco,

        >>= has type m a -> (a -> m b) -> m b. Our bind here is exactly the same thing. It takes a value on the left and a function on the right. The compose combinator I just wrote is Haskell’s >=> which has type (a -> m b) -> (b -> m c) -> a -> m c.

        Normally, in Haskell, you would chain things together like this:

        as >>= \a -> bs >>= \b -> cs

        Function literal syntax in Haskell is easy, so the >=> operator doesn’t get used much in practise.

  5. Very good example of the fact that Java sucks.. Functional Programming or fixing design/conceptual Errors is already too late. One may decide to live that than use verbose wrappers or functional frameworks.. which does not look natural for that original language. One may decide to jump over all those “enhancements” to different language – like Scala or (back) to Haskell. Just my feelings about that.

Leave a comment