Wednesday, February 17, 2010

Optional iterators right now...

Monads in terms of Java has been the topic that has caught my attention of late and while some of the articles out there have almost managed to penetrate my rather thick skull — I can almost see the potential benefits I can reap in terms of being able to design clean and easy to use apis — I still feel I am missing some crucial piece of information before the whole puzzle starts to make sense...

Oh well — maybe it's best to simply let it settle and let these ideas mature a little in my head (I am sometimes slow, like this).

Meanwhile I am getting kind of tired of all the boilerplate I have to write to get around potential NPE traps with this new and shiny for iteration syntax introduced in Java 5. Not that there is a lot to write, but it is kind of tedious and introduces something, that even has a nice buzzing name for it — "accidental complexity" into otherwise quite straightforward application logic.

So, I kind of remembered some nice features of Option/Maybe concept from monad articles I've read up and decided to borrow some of it to scratch my little itch...

Just take a look at this little piece of code:
public class Foo {
  // filled by some external process
  public static Foo[] fooball;

  public static void main(String[] args) {
    for (Foo foo : Optional.iterable(fooball)) {
      // ... do stuff to foo here
    }
  }
}

Now, I admit, the code above does not make any sense at all, except to illustrate a point.
Point being that I can safely iterate over an array of unknown origin, without having to worry if the array is null or not. Okay, I concede, I actually do have to worry about it, but I've tucked the little ugly piece of code nicely away where it does not poke me in the eyes every time I look at the code.

Magical isn't it?

Well, I wish it was magic. Then I could simply wave my magic wand, quit my job and conjure up piles of money to cover my mortgage and a nice palace to live somewhere nice and warm...

Joking aside, it is really kind of simple. Public interface to my Optional class is really simple:
public final class Optional {
  public static final <T> Iterable<T> iterable(Iterable<T> input) {
    ...
  }
  public static final <T> Iterable<T> iterable(T ... input) {
    ...
  }
}

That is almost it. The implementation details are actually quite straightforward — with the iterable as an input, you simply check if the input is null and return dummy empty iterable instead. With vararg/array input I return empty iterable for null or empty input array or wrap the array in a lightweight iterable instance if input array is not empty.

There is one more gocha with this approach — since I am using varargs to capture array type of input, there is a special case of only entering a single argument to varargs method. This can be somewhat confusing, since that single argument might also be null and I am not entirely sure what should I do in this case. At the moment it is treated as a one element array (as per vararg convention), whose value happens to be null.

I am currently considering adding another method to Optional class accepting only one argument and returning either an empty iterable if the value is null or a single-item iterable if it is not null.

Oh, an just to be clear on this - the implementation is not a monad by any stretch I am aware of... It simply borrowed a neat little trick from the functional approach of masking the null values with something useful.
Post a Comment