3 ms·
Boolean parameters aren't the problem. It's that people use booleans when they mean "something that has two choices", they're too lazy to enumerate what those c
by awalton 12y ago
Boolean parameters aren't the problem. It's that people use booleans when they mean "something that has two choices", they're too lazy to enumerate what those choices are, and most crucially, it cannot be easily inferred from context what the boolean argument means.
It's perfectly fine if your function takes a boolean argument where the parameter either means "TRUE" or "FALSE": EnableThing(bool) is self-descriptive (as long as passing TRUE enables the thing... too many APIs fall victim to this total failure as well).
The real problem is when you start using booleans where you lose the meaning. Mapping boolean to things that take on similar meanings { 0, 1 }, { NO, YES }, { OFF, ON }, and maybe stretching it a bit, { BLACK, WHITE } is probably okay as long as it is clearly spelled out what the flag is doing, and likely it should be the only parameter to the function (and definitely not when there are multiple flags, and especially definitely not when those flags have some interaction). Mapping boolean to { PURPLE, YELLOW }, { LEFT TO RIGHT, RIGHT TO LEFT }, or { SYNCHRONOUS, ASYNCHRONOUS } is asking for people to misuse your API, and worse - painting yourself into the corner when it comes time to handle BLUE, TOP TO BOTTOM, or ISOSYNCHRONOUS. In many of these cases, you're far better off just throwing in the ten second enum. ("Functions are cheap" is true for applications, but it's categorically false for libraries, especially those that must stand up to the test of time, so I would definitely stick to the enum - types really are cheap.)
His given example is definitely an example of doing it wrong, but I have a better one that I come across every day at my job:
gtk_box_pack_start (Box, Widget, bool expand, bool fill, int padding);
#1. Two boolean flags, so you must remember the ordering, or look it up every time.
#2. One boolean changes the behavior of the other. We don't have a complete mapping; only three of the four states are meaningful.
#3. The API is not expressive enough to tell you what expand/fill mean without looking at the documentation, so you have to "do the matrix" and start seeing blonde, brunette, redhead by memorizing the order of the flags.
An enumeration would tell you immediately, and be roughly as character efficient as "FALSE, FALSE", "TRUE, FALSE" or "TRUE, TRUE":
enum GtkBoxPackingOptions
{
PACK_SHRINK,
PACK_EXPAND_PADDING,
PACK_EXPAND_WIDGET
};
(And the latter enumeration is exactly what the gtkmm C++ bindings do.)
- Terr_ 12y agoSomewhat related to the "use an enum" approach: Value Objects. Not quite an enum since it's not a design-time constraint, but they can let you "wrap" a scalar (or series of scalars) into something much more self-documenting, and prevent mismatches, like where someone substitutes length for mass. For your example it'd be overkill since there are only four states, but if there was some additional related piece of information, like a number for tolerance, you could make an immutable object to group it all together.
- jbergens 12y agoIt also depends on the language. In c# enums aren't required to have defined value. But it would help as documentation for what values you were expecting.