Wednesday, June 3, 2009

Replacing Booleans with Enums for Great Justice

From time to time I see method signatures that look like the following contrived example:


public interface Copier {
public void copy (boolean readOnly, boolean fuzz);
}


If someone calling this function doesn't have access to the documentation or source code, they won't be able to see the names of the variables, and therefore will not know that the first variable signifies read-only status, and the second whether or not to use fuzz. This leads to coding by guesswork, which is a bad thing.

Enumerations can fix this:


public interface Copier {
public static final enum ReadMode {READ_ONLY, READ_WRITE}
public static final enum FuzzType {NO_FUZZ, REGULAR_FUZZ}

public void copy (ReadMode readOnly, FuzzType fuzz);
}


This means that the developer does not have to look up documentation to see what each argument is for, and the compiler will shout at people if they mix up the parameters.

This way of doing things is also much more extensible. Suppose the code needed to handle a new type of fuzz for the latest version of the product: super fuzz. The FuzzType implementation could easily be replaced with the following:


FuzzType {NONE, DEFAULT, SUPER}


Although this breaks the API, it does so in a less destructive way than changing the type of the fuzz parameter - the code will still compile, anyone using a default clause in their case statements (or else clause in their if statements) will already be able to handle the API change, most of the time things will continue working and babies will not die. Another sticky situation occurs if a client iterates over the enumeration. If the client does this, then (according to Murphy's Law) the client will do something bad and things will break.

Replacing booleans with enumerations is not a new idea (others have suggested similar things) and, like anything, is not a silver bullet: an enum takes up space just like any other class, which is less efficient space-wise than using a boolean; a third possible value (null) is added which should be checked for; and the code becomes a little more complex. The main benefit from using an enum instead of a boolean is self-documenting code.