5

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

3

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).

8

In the line with @Ewan’s answer, choose the one that makes 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 to whoever is reading. And it’s unbearable when flags have meaningless names.

Negation always involves an extra cognitive step (even when the negation is involved in the name of the flag). We usually think first in the is part and then we negate it. So, the more your if statements look like the following, the easier to read them

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

I know this is easier to say than done. 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. That’s ok, we can address it later. For example, we can invert the flag isA = !isNotA and use isA in conditional statements. 1

Summarizing, use the one that makes your code easier to read (meaningful names) and easier to reason about (to me, affirmative statements). And avoid negations and double negations in conditional statements as the plague, your coworkers 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

3

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
}

5

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.

5

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.

1

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *