Boolean Trap – How to Make Boolean Calls Clearer

booleanconst

As noted by in the comments by @benjamin-gruenbaum this is called the Boolean trap:

Say I have a function like this

UpdateRow(var item, bool externalCall);

and in my controller, that value for externalCall will always be TRUE. What is the best way to call this function? I usually write

UpdateRow(item, true);

But I ask my self, should I declare a boolean, just to indicate what that 'true' value stands for? You can know that by looking the declaration of the function, but it's obviously faster and clearer if you just saw something like

bool externalCall = true;
UpdateRow(item, externalCall);

PD: Not sure if this question really fits here, if it doesn't, where could I get more info about this?

PD2: I didn't tag any language 'cause I thought it was a very generic problem. Anyway, I work with c# and the accepted answer works for c#

Best Answer

There isn't always a perfect solution, but you have many alternatives to choose from:

  • Use named arguments, if available in your language. This works very well and has no particular drawbacks. In some languages, any argument can be passed as a named argument, e.g. updateRow(item, externalCall: true) (C#) or update_row(item, external_call=True) (Python).

    Your suggestion to use a separate variable is one way to simulate named arguments, but does not have the associated safety benefits (there's no guarantee that you used the correct variable name for that argument).

  • Use distinct functions for your public interface, with better names. This is another way of simulating named parameters, by putting the paremeter values in the name.

    This is very readable, but leads to a lot of boilerplate for you, who is writing these functions. It also can't deal well with combinatorial explosion when there are multiple boolean arguments. A significant drawback is that clients can't set this value dynamically, but must use if/else to call the correct function.

  • Use an enum. The problem with booleans is that they are called "true" and "false". So, instead introduce a type with better names (e.g. enum CallType { INTERNAL, EXTERNAL }). As an added benefit, this increases the type safety of your program (if your language implements enums as distinct types). The drawback of enums is that they add a type to your publicly visible API. For purely internal functions, this doesn't matter and enums have no significant drawbacks.

    In languages without enums, short strings are sometimes used instead. This works, and may even be better than raw booleans, but is very susceptible to typos. The function should then immediately assert that the argument matches a set of possible values.

None of these solutions has a prohibitive performance impact. Named parameters and enums can be resolved completely at compile time (for a compiled language). Using strings may involve a string comparison, but the cost of that is negligible for small string literals and most kinds of applications.