Tuesday, July 1, 2008

The Enum is perfect... well almost.

Ok so its time to admit to something. I'm deeply in love with Java's Enum! In my opinion it was the best part of Java 5 and I still wonder why it took Sun 10 years to add this powerful static modeling construct.

The power of the Enum
Although there certainly are known limitations of the Enum, i.e. how you can't extend it, I have never run into a practical limitation myself. Until now that is. The issue I want to raise is that of Enum forward referencing.

The great Alan Turing taught us that at the end of the day, everything can be modeled by a Turing Machine and finite automata. We may not often consciously operate at this level, but many things still makes sense to model this way being it a regular expression matcher, navigation rules or similar. The Java Enum appears to be a perfectly simple, fast and type-safe way of modeling this... or does it?

State machine with an Enum
Since the Java Enum effectively is just a group of static class instances, it allows us to attach methods and state to each static instance. We should be able to use this fact to express a transitive relationship with outself. To model a CD player, we'd write something like this:



public enum PlayerState {
STOPPED(PlayerState.PLAYING),
PLAYING(PlayerState.STOPPED, PlayerState.PAUSED),
PAUSED(PlayerState.PLAYING, PlayerState.STOPPED);

private final EnumSet<PlayerState> transitions;

PlayerState(final PlayerState... transitions){
this.transitions = EnumSet.copyOf( Arrays.asList(transitions));
}

// State transition and query logic below...
}


Except that won't compile! The compiler complains with an "illegal forward reference" error. I can understand why it's the easiest to simply not allow this circular use case, but considering everything else in Java allows forward referencing (i.e. we don't need header files as in C++) it would've been nice if that was the case with Enum's too.
The JLS simply states:
"It is a compile-time error for the constructors, instance initializer blocks, or instance variable initializer expressions of an enum constant e to refer to itself or to an enum constant of the same type that is declared to the right of e"
Granted, it has been some years since my last compiler course but I can't see any reason not to allow forward referencing in this particular case where everything is known. I suspect the culprit simply being that Enum, as with so many other things, was added later using only existing features such as not to change existing initialization rules of the JVM.