ADT-like polymorphism in Java (without altering class)

algebraic-data-types, haskell, java

Solution

Try something like this.

Sorry, my Java is very rusty. If, unlike me, you can remember the syntax, you could use Java generics to refine `Object` to `Integer` or whatever class the method you're writing needs. But you can't (can you?) return primitive types, sorry.

interface TreeFolder {
    Object onEmpty();
    Object onLeaf (int n);
    Object onNode (Tree l, Tree r);
}

interface Tree {
    Object fold (TreeFolder f);
}

class Empty implements Tree {
    Object fold (TreeFolder f) {
        return f.onEmpty();
    }
}

class Leaf implements Tree {
    private int n;
    Object fold (TreeFolder f) {
        return f.onLeaf (n);
    }
}

class Node implements Tree {
    private Tree l, r;
    Object fold (TreeFolder f) {
        return f.onNode (l, r);
    }
}

// meanwhile, in a class in another package far far away...
Object depth (Tree tree) {
    return tree.fold (new TreeFolder() {
        Object onEmpty() { return new Integer(0); }
        Object onLeaf (int n) { return new Integer(n); }
        Object onNode (Tree l, Tree r) {
            Integer ll = (Integer) l.fold (this);
            Integer rr = (Integer) r.fold (this);
            return new Integer (ll.intValue() + rr.intValue());
        }
    });
}

Note that in `depth()` I have to manually recurse (call `fold()`) on the `Tree` parameters. You could instead choose to recurse on them upfront in `Node.fold()` (and change `TreeFolder` accordingly), but then you have to recurse --- you can't choose to recurse only into the left subtree, should you wish to. (In Haskell we don't have to make that trade-off thanks to laziness.)

Problem

In Haskell I can define following data type: ``` data Tree = Empty | Leaf Int | Node Tree Tree ``` and then write polymorphic function like this: ``` depth :: Tree -> Int depth Empty = 0 depth (Leaf n) = 1 depth (Node l r) = 1 + max (depth l) (depth r) ``` In Java I can emulate algebraic data types with interfaces: ``` interface Tree {} class Empty implements Tree {} class Leaf implements Tree { int n; } class Node implements Tree { Tree l; Tree r; } ``` But if I try to use Haskell-like polymorphism, I get an error: ``` int depth(Empty node) { return 0; } int depth(Leaf node) { return 1; } int depth(Node node) { return 1 + Math.max(depth(node.l), depth(node.r)); // ERROR: Cannot resolve method 'depth(Tree)' } ``` Correct way to overcome this is to put method `depth()` to each class. But what if I don't want to put it there? For example, method `depth()` may be not directly related to `Tree` and adding it to class would break business logic. Or, even worse, `Tree` may be written in 3rd party library that I don't have access to. In this case, what is the simplest way to implement ADT-like polymorpism? Just in case, for the moment I'm using following syntax, which is obviously ill-favored: ``` int depth(Tree tree) { if (tree instanceof Empty) depth((Empty)tree) if (tree instanceof Leaf) depth((Leaf)tree); if (tree instanceof Node) depth((Node)tree); else throw new RuntimeException("Don't know how to find depth of " + tree.getClass()); } ```

Original source