Home > API and Patterns > Boolean parameters considered harmful – almost

Boolean parameters considered harmful – almost

I have to admit this blog’s title is a bit exaggerated, but since I have lately seen some bad examples of using booleans as parameters, I just felt the urge to write about it.

Code is more often read than written, so readability is a great concern in programming and often it’s the small things that make things worse and can it get smaller than a boolean? The other big issue with programming in general is that code must be maintainable, so it must be easy to change it. Sometimes it needs to be cleaned up, sometimes functionality has to be added, so ripple effects is something we don’t need.
For both reasons I have noticed myself using less boolean parameters every day.  Today I would even state that using a boolean parameter is a bad idea in most cases. Let me demonstrate my point with a little example:

<T extends Component> T find(final Class<T> type,String name,final boolean descend,final Component... components){
 T result=null; 
 if (components != null){
  for (int t=0; result==null && t<components.length; ++t){
   final Component candidate=components[t]; 
   if (type.isInstance(candidate) && equals(name, candidate.getName())) {
    return type.cast(candidate); 
   } else if (descend && candidate instanceof Container){
    result = find(type,name,descend,((Container)candidate).getComponents());
   }
  }
 }
 return result;
}

This code doesn’t look suspicious, but the ugly gets apparent when this method gets used:

Component x = find( Button.class, "button", true, root );

If you see a line like this in a program, you usually have no idea what ‘true’ stands for, until you dig into the code of the method – which gets worse if the sourcecode is not available.
And what if you need to introduce scanning upwards in the hierarchy? You would need to change the API significantly and break every method that uses this API. Or you’d need to introduce a new method which will probably make you copy code or deprecate the old method (which you will never get rid of).

So usually it’s a better strategy to use an enumeration, which creates a few more lines of code, but just have a look:

static enum Search{
 FLAT, DESCENDING;
}

<T extends Component> T find(final Class<T> type,String name,final Search strategy,final Component... components){
 T result = null;
 if(components != null){
  for(int t=0; result==null && t<components.length; ++t){
   final Component candidate = components[t];
   if(type.isInstance(candidate) && equals(name,candidate.getName())){
    return type.cast(candidate);
   } else if (strategy==Search.DESCENDING && candidate instanceof Container){
    result=find(type,name,strategy,((Container)candidate).getComponents());
   }
  }
 }
 return result;
}

The full beauty of this API is visible when it is used, just have a look at this:

Component x = find( Button.class, "button", Search.DESCENDING, root );
Component y = find( JPanel.class, "rightPanel", Search.FLAT, root );

Just by looking at the code you could guess what the parameter does.

This API also supports enhancing the functionality way better. To implement scanning upwards the hierarchy, just modify the enumeration and add some lines to the method:

static enum Search{
 ASCENDING, FLAT, DESCENDING;
}

<T extends Component> T find(final Class<T> type,String name,final Search strategy,final Component... components){
 T result = null;
 if (components != null) {
  for (int t = 0; result == null && t < components.length; ++t) {
   final Component candidate = components[t];
   if (type.isInstance(candidate) && Utils.equals(name, candidate.getName())) {
    return type.cast(candidate);
   } else if (strategy == Search.DESCENDING && candidate instanceof Container) {
    result = find(type, name, strategy, ((Container) candidate).getComponents());
   } else if (strategy == Search.ASCENDING && candidate != null) {
    result = find(type, name, strategy, candidate.getParent());
   }
  }
 }
 return result;
}

So here it is: I’ve enhanced the functionality without breaking the old API just by adding an enumeration and another branch.

Component x = find( Button.class, "button", Search.DESCENDING, root );
Component y = find( JPanel.class, "rightPanel", Search.FLAT, root );
Component z = find( TabbedPane.class, "tabs", Search.ASCENDING, textField );

The old stuff still works, it is still readable. A much better solution than a boolean.

Now just imagine the Swing API, if it looked a little bit like:

jFrame1.setState(State.MAXIMIZED);
jFrame2.setState(State.RESTORED);
jFrame3.setState(State.MINIMIZED);
jFrame4.setState(State.ICONIFIED);
jFrame5.setState(State.INVISIBLE);

Advertisements
  1. Stephan
    March 12, 2010 at 16:57

    You left out the even worse case: multiple boolean arguments. One boolean argument might not be /that/ bad, but two or more becomes impossible to read. Where can I vote for a ban of boolean arguments? đŸ˜‰

    Also: Nice articles! Hope to read more from you in the future.

  2. javafinanceguy
    April 10, 2010 at 22:29

    classic issue.
    especially if you’re using a library class and not enuff or no javadoc is available. its next to impossible to know what the hell is param supposed to do.
    but you can’t blame folks, we didn’t have enum for some time now [other than final static constants]. hopefully people use more of it.

  3. Heiko
    April 13, 2010 at 12:11

    Hi Wanja,
    THANK YOU! I wished more people would read (and understand) your article. Really nice one! Just subscribed …

    • April 14, 2010 at 07:30

      Thanks for the feedback guys. Good to know I’m not the only one who feels this way.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: