I just learned that "foray" is a rather violent word: "a sudden attack into enemy territory." I was under the impression that it meant an experiment or exploration of something completely new. Now that I think about it, I'm happy with this more aggressive definition. I like to think that I'm aggressive about writing less code, especially after reading "Code's Worst Enemy" by Steve Yegge .

I was writing an HTTP endpoint in Java with the following type signature:

uuid, field to sort by, sort order -> [ list of data objects in order ]

As a concrete example, suppose we are working with students and schools. This endpoint would allow us to do things like fetch a list of all the students at a given school in alphabetical order by last name. Such a query might look like this:

school$4$g1fted$and$talent3d$5tudents$uuid, lastName, ascending

and return something like this:

[Student:[lastName:Aebersold
          firstName:Jamey
          school_id:school$4$gifted$and$talented$students$uuid]
... ]

The question I ran into was how to define what the sort by parameter is. One option would be to define a whitelist of sortable fields represented in Java as an enum and then implement Java Comparators for each one. When all the boilerplate was said and done, each comparator would amount to various incarnations of

return student1.getLastName().compareTo(student2.getLastName());

for each sort by field. Instead, I decided that I wanted to be more aggressive and try out this Java reflection thing that I've heard so much about. This is what I wound up with:

/**
 * Returns a Comparator on {@code T} given the field to sort by as a string
 * and the orientation: positive for ascending and negative for descending.
 */
private <T> Comparator<T> getComparator(final String sortBy,
    final int orientation, Class<T> clazz)
        throws NoSuchFieldException {
final Field field = clazz.getDeclaredField(sortBy);
field.setAccessible(true);

return new Comparator<T>() throws Exception {
    @Override
    public int compare(T status1, T status2) {
    try {
        Object f1 = field.get(status1);
        Object f2 = field.get(status2);
        if (f1 instanceof Comparable<?> && f2 instanceof Comparable<?>) {
        Comparable c1 = (Comparable) f1;
        Comparable c2 = (Comparable) f2;
        return orientation * c1.compareTo(c2);
        } else {
        throw new RuntimeException("Unsortable field: <" + sortBy + ">");
        }
    } catch (IllegalAccessException e) {
        // TODO: throw a more specific exception.
        throw new Exception("Unsortable field: <" + sortBy + ">");
    }

    throw new UnsupportedOperationException();
    }
};

This was surprisingly fun and satisfying. Looking at it now, I can make a number of observations:

  1. It's really cool how Field objects take object objects as parameters, e.g. field.get(status1).
  2. The implementation of orientation is bad Java and bad programming in general. It should be an Enum which has meaning to humans and not just the computer, or mathematicians who have a particular understanding of what orientation means.
  3. Having types makes me feel safe. There's something nice about having a return type of Comparator<T> where the type T is being enforced throughout the method.

Of course, if you are willing to give up some type safety and write this in plain old untyped Clojure, you can get a similar procedure in five lines of code:

(defn get-comparator
  [sortby]
  (fn [x1 x2]
    (compare (get x1 sortby)
             (get x2 sortby))))

I think the deeper lesson here is that the complexity of the Java method springs from the fact that in Java, data is often hidden behind a particular class' getter/setter DSL. Though, is that better than hard setting hash map keywords that is common in Clojure? Dunno.