Getters break encapsulation

Scala has the concept of case classes. Case classes are really simple classes with immutable fields that can be defined really succinctly.

We can define a similar class in Java, which while a little larger is also very explicit about what the compiled classes structure will actually be.

Once created, however usage is very similar

Scala case class usage

Java case class usage

Except in one regard, in the abscence of a catamorphism Java implementation for Book we can pattern match in Scala but not in Java

But this is easily fixed

In Java, we now have the additional option of making our case class members private and forcing all access through the catamorphism. The benefits of doing so for a simple class like our Book example are minimal, but as we have seen with Optional even a little additional complexity means errors can begin to seep into our code base. Let’s see this in action, by introducing two new subclasses of Book — Fiction and Nonfiction.

Either Fiction or Nonfiction

We can refactor our Book class making a couple of changes

We make Book an abstract class, as we now have two concrete types (Fiction and Nonfiction instead) We define the two sub-types (Fiction and Nonfiction) We make all fields private (to keep the code that uses our Book instances simple!)

There are a few notable properties of this class, the only concrete types of Book that are definable are Fiction and NonFiction. This is enforced by the private constructor. Additionally all access to the internal state or structure of our Book instance is controlled via our original catamorphism.

How do we handle fiction and nonficton differently

Now we have two types of Books we may be tempted to process them via the traditional Java if / then / else statement.

Even for such a relatively trivial example, if / then / else can cause bugs : note the semicolon! a is alway 1

A better approach is to define another catamorphism that folds over the possible types of Books. The implementation for this would look very like our implementation for Optional, except that we would accept two single parameter functions. One would receive Fiction instances and the other Nonfiction instances.

catamorphism over Book type

We can rewrite our buggy if / then / else statement to one that is much more safe

The catamorphism for an Either (or Xor type)

We have just derived the catamorphism for a Book that can either be Fiction or Nonfiction. This can be generalized to account for a type that can either be one of two other types (e.g. type T1, type T2). A common datastructure to represent this is an Either type. (cyclops-react provides lazy & reactive implementations of Either for up to 5 choices and an eager version of the datastructure called Xor — eXclusive or). Much like how we can use Optional when a field is nullable, rather than consistently reimplement Eithers to represent inheritance hierarchies we can make use of the existing datastructure.

We can refactor our Book class to use Either instead

An to pattern match on the type of Book we can use the match method

The catamorphism for a List

When Lists are implemented in functionally, they are normally structured (recursively) in terms of a head and a tail

Head : first value Tail : List containing a Head and a Tail

The catamorphism for a List would consist of a two parameter function (or BiFunction) that accepts both the first value of the list, and the tail (the rest of the list). We can easily implement this using the eXtended List type (ListX) in cyclops-react. ListX can wrap any standard j.u.List and adds a lot of useful fucntionality. Even though j.u.Lists are not (typically) implemented in terms of a Head and Tail, we can abstractly (or virtually) represent them as such and our simple catamorphism can still be applied.

With Scala pattern matching we can fold (or reduce) a List of Strings to a single String, by appending the head and recursively processing the tail.

In Java with our List catamorphism we can essentially do the same thing

Implementing your own catamorphisms

In this article we showed how simple it was to implement a catamorphism (or pattern matching) for one of the core Java 8 types — Optional. Then through a worked example, we implemented a very simple Case Class in Java with it’s own catamorphism. We showed how catamorphisms can simplify working with inheritance hierarchies in Java, by implementing the catamorphism for an Either type. Finally we implemented the functional catamorphism for a j.u.List even though it does not expose the simple recursive data structure of a head and a tail.

All of these catamorphisms were implemented in 3 lines of code or less, but they allowed us to pattern match on the important aspects of the structure of the types we created them for. You can do this in your own code base too.

Next time you find yourself wrangling with a gnarly if / then/ else sequence or case statement ask if this can be simplified somehow, almost certainly there is something about the structure of your Objects that can guide you in creating simple catamorphisms that will improve the robustness of your code.