11

In many cases I can formulate some boolean parameter equally well positively as negatively, e.g. isOn or isOff. Which one should I pick then, in case I want the argument to have a default value? Is there a convention that an optional boolean function argument should rather default to false than true? Or the other way around?

I know that often it is better to avoid boolean function arguments altogether, but in some cases a named boolean function argument IS the best solution IMHO. So I am more interested in answers to my question than advice to avoid the boolean argument.

4
  • 1
    It really depends on what the argument means and what it used for. Sometimes defaulting to true is better, sometimes it should be false
    – f222
    Commented Sep 6, 2022 at 7:41
  • 10
    Yes, this is like asking "I want to find a good method name, are vowels or consonants better?". A boolean only means something in its context, the context decides which default makes sense. Commented Sep 6, 2022 at 7:51
  • 3
    Whichever one makes more sense, semantically, from the point of view of who/whatever is calling the function. And if those who are calling the function don't really care then is about as useful as a decision whether to paint the bikeshed purple or turquoise. Commented Sep 6, 2022 at 7:55
  • 1
    I see that you don't want to hear it, but it is better to offer two methods instead of a boolean parameter if the callers know at each call site which constant value to choose. The boolean parameter version can still be offered, but then it will not need to be optional or have a default value -- should only be used by callers that will pass a variable/non-constant expression.
    – Erik Eidt
    Commented Sep 6, 2022 at 15:13

5 Answers 5

6

I agree that you should go with what makes more sense semantically, but I also find that, when the boolean argument is optional, the thing that fairly often makes more sense when omitting it is for it to have a default value of false - in languages that initialize instances of primitive types, false is generally the default value for a boolean.

It then acts as an "on" flag for the less commonly used feature. So that you have:

DoSomething(someParams);
DoSomething(someParams, true);

// Or, if your language supports named parameters
DoSomething(someParams, optionalFeature: true);

So, I would have a slight bias for the parameter to default to false, unless doing so feels unnatural (as in, it feels unnatural as a sentence when you read it). Sometimes, the exceptional behavior is better conceptualized as turning something off (for example, setters that take a boolean argument are often constructed this way, see Joop Eggen's answer; however, you should strive for encapsulation, and minimize the use of getters and setters).

If the feature controlled by the boolean argument is not less commonly used (in the general case), I wouldn't make it optional. Design for the general case. If there's a small number of users with applications that mostly use one value for the argument, they can create their own wrapper.

As for the logic inside the method, if it turns out that your choice makes it awkward to write conditionals, just introduce a new well-named variable with the flipped value (or a new variable that summarizes several boolean checks that repeat, or whatever) - it's not going to be a problem if your method is fairly short (which it should be - you shouldn't have a sprawling tree of nested if-statements in there).

10

In line with @Ewan's arguments, choose the one making the code easier to read and reason about.

For example, double negations (!isNotA or Ewan's !FileDoesntExist) are the kind of conditional statements you want to avoid because they cause a cognitive burden. Unbearable when flag names are meaningless.

Negation involves an extra cognitive step (even when the negation is in the name of the flag). We usually think first in the is part and then negate it. So, the more your if blocks look like the following, the better

//only for illustration
if(isA && isB)
else (isA)     //isA && !isB
else (isB)     //!isA && isB
else           //!isA && !isB

Ok, this is easier to say than done, but think about it. It depends on how we translate (mentally) rules into conditions. If we think in terms of "is not", we will end up with flags prefixed with isNot, and it's ok if we can address it later. For instance, we can invert the flag isA = !isNotA and use isA instead. 1

To summarize, use the notation that makes your code easier to read (to me, affirmative statements), always use meaningful names and avoid negations and double negations as the plague; your teammates will appreciate it.


1: Do it only to make your conditionals easier to read and reason about. Don't systematically invert flags all over the code.

2
  • 2
    Don't not avoid negatives. DeMorgans law can be used for good and for evil. Choose wisely. Commented Sep 8, 2022 at 19:30
  • Sometimes you cannot and turning them into positives doesn't help. That's fine. But keep always in mind the double negation... Generally speaking, readability is more important (IMO). If it's understandable, then it's ok.
    – Laiv
    Commented Sep 10, 2022 at 1:33
4

You should choose the one that will favour the most common use of calling code.

eg

if(FileExists) //good
{
   //do something to file
}

vs

if(!FileDoesntExist) //bad
{
    //do something with file
}
6
  • These are two different arguments (default to most common, avoid double negation), right?
    – DaveFar
    Commented Sep 8, 2022 at 6:54
  • hmmm, you could probably have something that returned true when there wasn't a file but with better naming. SpaceFree, FilenameAvailable I dont think it matters as long as you are thinking "what makes most sense for the calling code" rather than following "always default to true!" or something
    – Ewan
    Commented Sep 8, 2022 at 8:14
  • Sorry, what I meant: These are two different reasons you are giving (default to most common, avoid double negation), right?
    – DaveFar
    Commented Sep 8, 2022 at 8:48
  • no not really, its about how you use the code, if the use is to check if the file exists, have fileexists, no something else that means teh calling code has to do extra stuff
    – Ewan
    Commented Sep 8, 2022 at 9:02
  • You could use "fileNeedsCreating" instead of "fileDoesn'tExist" - obviously only if the fact that a file doesn't exist means it needs creating. You can actually have both if the fact (file exists or not) might not agree with what you want (you want to create the file).
    – gnasher729
    Commented Sep 8, 2022 at 19:01
3

With the following it is clear that true should be the default value (especially with setVisible).

void setVisibility(boolean visible) { ... }
void setVisibility() {
    setVisibility(true);
}

Below the version defaulting version is more like a false, but actually has different semantics.

public FileWriter(File file) throws IOException
public FileWriter(File file, boolean append) throws IOException

There is in general a notion that the number of parameters should not grow to provide different cases. Using a parameter class, you might limit the API, and provide a more meaningful usage:

Foo foo = new Foo();
Foo.Params params = new Foo.Params();
params.setNum(42);
params.setPosition(32, 480);
params.setBaz(true); // <--- optional call
foo.bar(params);

In general extras should default to false, shouldn't it?

And goodies should default to true.

I do not think there is some rule. And thus default parameters are dubious.

7
  • w.r.t. your conclusion 'thus default arguments are dubious' - weakly true for default parameters in general, strongly true for boolean default parameters, and - IMO! - moderately true for boolean parameters in general.
    – davidbak
    Commented Sep 6, 2022 at 17:15
  • 1
    @davidbak yes, true/false being clueless. Many int parameters too.
    – Joop Eggen
    Commented Sep 7, 2022 at 6:05
  • Dubious also for NAMED arguments?
    – DaveFar
    Commented Sep 8, 2022 at 6:57
  • What is a goody, what is an extra? Isn't a goody and extra?
    – DaveFar
    Commented Sep 8, 2022 at 6:57
  • 1. Named arguments, builder pattern, parameter class with setters, all those make things explicit and are fine for many arguments. 2. Goody and extra are intentionally almost synonyms. What is superfluous should default to false, like line break in Base64 encoding. What is good to have per default like charset UTF-8 (full Unicode) should default. Of course that kind of argumenting is a tautology, self-evident. Filip Milovanović did give a nice answer.
    – Joop Eggen
    Commented Sep 8, 2022 at 7:27
2

If you have an optional argument, the argument should usually not be passed to the call. If you have an optional bool argument, I’d say 80% of calls should have no argument passed, and the default value is the 80% case. Less than 80% don’t use a default. YMMV)

An exception could be setters where reading the setter call without argument makes sense. For example, both x.setVisible() and x.setInvisible() would have obvious meaning.

(x.setVisibility() has no obvious meaning, so I would avoid naming it like that).

Now look at a call with the default omitted and assume it wasn’t a function with a default value but an ordinary function without that parameter, implemented by calling the function with the parameter. And that nobody told you about the function with parameter. And now it is clear that since things should be self documenting, the call without parameter should do what the caller expects. setVisible(true) and setInvisible(false) will obviously do the same thing. But I’d expect setVisible() and setInvisible() to do the opposite of each other.

3
  • I agree that the default should cover >80% of the cases. But should the name be chosen so that it defaults to false?
    – DaveFar
    Commented Sep 8, 2022 at 7:01
  • @DaveFar That doesn’t make sense. Make the default true if 80 percent of calls would use true. Make the default false if 80% of the calls would use false.
    – gnasher729
    Commented Jun 7, 2023 at 17:37
  • Let's say something is "on" in 80% of the cases. So I can define the argument isOn and make it default to True or I can define the argument isOff and make it default to False. Which one should I pick? That's what the question is about.
    – DaveFar
    Commented Jun 8, 2023 at 15:51

Not the answer you're looking for? Browse other questions tagged or ask your own question.