Tuesday, March 16, 2010

Fun with null objects

I'm doing some heavy lifting in Java for the first time in a few years, as I'm writing a wiki parser for FitNesse. I came across the good old Null Object pattern as I was rendering the HTML output from the parser:

String translation = currentToken.render(scanner);
Since I'm using a backtracking parser design, this operation may fail. So how do I communicate that to the caller? Of course, I can return null and check for that. But passing nulls around is something I try to avoid at any cost. Well, any reasonable cost. I could throw an exception, but this isn't really an unexpected situation or an illegal operation, it's part of normal operation. I could also add a method to check if I need to backtrack:

if (currentToken.canRender(scanner)) { String translation = currentToken.render(scanner); ... }
However, canRender() could be very expensive as it might have to do all the work that render() does. Often, I wouldn't worry about this, but one of the goals of this parser is to be high-performance. I could cache the results of the work that canRender() does so that render() wouldn't have to duplicate it. But then my design is getting more stateful and more complicated, and my experience tells me to avoid that if possible.

So I decided to return an object that can tell the caller if the operation worked, and if so, what the result is. There's probably a Java idiom for doing this, but not knowing what that might be, I came up with my own:

Maybe<String> translation = currentToken.render(scanner); if (!translation.isNothing()) { result.append(translation.getValue()); ... }
Here's my implementation of the Maybe class:

public class Maybe<T> { public static final Maybe<String> noString = new Maybe<String>("*nothing*", true); private final T value; private final boolean isNothing; public Maybe(T value) { this(value, false); } private Maybe(T value, boolean isNothing) { this.value = value; this.isNothing = isNothing; } public T getValue() { return value; } public boolean isNothing() { return isNothing; } }

Update: Nat Pryce, whose Java skills are infinitely greater than mine, has posted his implementation.

No comments:

Post a Comment