1

Most programmers (including me) believe that methods with a boolean flag parameter should be refactored into two methods without the flag parameter. Are there any use cases for a boolean parameter where it isn't a flag? I haven't been able to think of any. However, just because I can't think of an example doesn't mean that one doesn't exist.

I'm after an example where at least 90% of programmers would agree that a boolean parameter makes the most sense, produces the cleanest, most elegant code, etc. That is to say, the use case should be fairly uncontroversial. The method should use the boolean value itself and not simply pass it through to some other method. If you believe there can never be such an example, please explain your rationale.

The boolean shouldn't be retrieved by your library or passed to another (that's an interface design issue).

class BooleansAreNotFlags {
  function foo() {
    bool a_non_flag_boolean = result_of_calculation_or_logic();
    bar(a_non_flag_boolean);
  }

  function bar(bool not_a_flag) {
    // do something with not_a_flag
  }

What code could go into function bar(bool) {} where refactoring the boolean out of it would make it worse? If you can only think of an example with more than one parameter, that's OK too.

CJ Dennis
  • 669

8 Answers8

19

I have one

assert(a == 1);

Why is this OK? Because the boolean is the point of this interface. No one has trouble remembering what it means. That's not always the case so the advice to consider refactoring when faced with boolean flags still stands.

candied_orange
  • 119,268
7

It all depends on the definition of boolean flag:

  • for some, every boolean is a boolean flag. By induction every parameter would then just be a packet of flags grouped for the convenience of a higher purpose. Ultimately, according to your statement, any parameter passing would be a smell. Seriously ?
  • for some, only certain kind of arguments are a flag. It’s when you try to make different actions with the same function depending on the parameter. But then, how much different is different ? After all, print(char a) will do 256 different things depending on a, whereas print(bool b) would do only two different things. Why would the first be ok and the second a smell ?

So either we conclude that every parameter passing is a smell, which is absurd, or we accept that booleans can be data like any other.

Of course, bad function design can happen with boolean parameters (e.g. coupling unrelated actions in a single function), but exactly as with other data types as well (e.g. using integer options to choose between more than 2 alternatives).

Examples?

Just take any function where the boolean corresponds to a status/condition: user.setMarried(false)): Don't tell me that it should be refactored into user.setSpouse(otheruser), because if you don't need to know the spouse identity the refactoring wouldn’t be GDPR compliant ;-)

Edit: You could indeed consider that this can be refactored in setMaried() and setSingle(). But as consequence, you'd need to make the difference between the cases in your code whenever you want to move that data. So the simple a.setMarried(b.getMarried()) would become if(b.getMaried()) a.setMarried() else a.setSingle()). In the end, handling boolean data differently than non boolean types might result in transgressing the law of demeter.

Christophe
  • 81,699
3

If an If statement needs to be repeated very often to determine which of the two method should be called. I could definitely see it being better to have that if statement inside the method instead.

the_lotus
  • 153
2

just because a re-factoring of a bool parameter produces 'only' two functions, doesn't mean it's always a good idea to re-factor.

Do you have a source for your statement 'most programmers believe'?

What about serialization? would you have two methods, one for serializing true, and one for serializing false?

Aganju
  • 1,473
2

The use of boolean parameters has been frowned upon by Robert C. Martin (Uncle Bob) in his clean code video series for a reason. It doesn't need to be bad all the times. There are many in the industry who recognize that it is easy to produce bad code with boolean parameters. Refer here and here for more info.

A bool will always flag: A boolean variable has only two states (true and false). So a boolean variable can not be used for anything but flagging. So a boolean parameter will always act as a flag to a function.

Now the question is why is flag parameter to a function bad. A flag parameter in the function doesn't cause any harm to the body of the function. It reduces the calling code's readability.

Example 1: Consider the below code for computation of simple and compound interest. The readability of the function body is not bad. But if you look at the calling code in isolation it's difficult to say if we are trying to compute simple interest or compound interest with out looking it to the signature of the method. So the readability of the calling code is compromised. If we refactor this method into two methods, then the calling code will have better readability.

Function definition

int ComputeInterest(int principal, int period, int rate, bool isSimple)
{
   if(isSimple)
   {
      return something;
   } else {
      return somethingelse;
   } 
}

Calling code

//Looking at the lines below difficult to say which is simple interest and which is compound
var x = ComputeInterest(1000,1,10,true); //ComputeSimpleInterest(1000,1,10) is more readable
var y = ComputeInterest(1000,1,10,false); //ComputeCompoundInterest(1000,1,10) is more readable

Example 2: Imagine a code to mark an order complete. It has an optional parameter to send a mail.

MarkOrderComplete(string orderId, bool isMailRequired);

//Now looking at the calling code, it will be difficult to say where we will be sending the mail and which will not be

MarkOrderComplete("ord12345", true); //CompleteOrderWithMail("ord12345") is more readable
MarkOrderComplete("ord123456", false); //CompleteOrder("ord123456") is more readable

Example of boolean parameter being good: The above examples really make boolean parameter a bad choice. However there are cases when it can be good as pointed out by candied_orange here

AssertTrue(bool isEqual, string message)
{
   if(!isEqual) throw new TestFailedException(message);
}

AssertTrue(5 == numberOfMonths, "Number of months is not equal"); //There is no readability issue here.

AssertTrue((5 < numberOfMonths ) && ( 10 > numberOfMonths), "Number of months is not okay"); //There is no readability issue here.

//AssertTure with boolean parameter gives as different ways to assert without loosing readability

Nachiappan Kumarappan
  • 1,464
  • 1
  • 11
  • 19
1

Technically, one never needs a boolean flag as a method parameter. Boolean flags are so popular because they are the physical "incarnation" of bits. In practice, boolean values are simply the elementary unit of information, as they have the smallest possible domain (2 different possible values). For this reason, they are extremely pervasive, but they are only within context when coding at a very low level.

As a result, multiple boolean values make up other pieces of information through composition. When did you last think that your int values are simply 32 (or 64) "booleans" packed together. You could always use an int to branch, only your domain would be vastly increased, so there is no practical use for this.

In short, "boolean flags" are at the heart of information theory (call them bits), and their value is, usually, a "static" one, i.e. they are used to represent information. Because, in isolation, they represent only two different cases, programmers thought it would be a great abstraction for... alternatives?! (I wouldn't know how else to call a conceptual analog...). So, there you have it. When we use our human mind, we very.. very very often think in terms of choices, and all that often in terms of mutually exclusive choices, and, as it seems, even more often in terms of pairs of mutually exclusive choices. Booleans seemed a great fit, so "we" embraced them naturally!

In simple words, "we" seem to make a pattern out of whatever bears significant resemblance to our natural abstracting mode of human thought.

By the way, even if you refactor a boolean flag into two methods, how would you know which one to invoke, if not for some boolean flag, somewhere higher up the call hierarchy? In fact, all you gain is expressiveness, not total substitution.

Apart from that, I can only see a single valid use case that fits your definition/take at boolean flags, and this being the elementary information representation conversion:

Convert.ToString(bool value);

See, you have to check which of the two values this is, so, unless you prefer to have the following all over your codebase...

if (value)
    return "true";
else
    return "false";

you are probably better of with Convert.ToString(bool value); than booleanTrue() and booleanFalse() methods that, again, in my opinion, don't really add any value.

Vector Zita
  • 2,502
1

Generally I believe that bool (boolean) parameter is bad, however in one situation I used 6 boolean parameters and my code reviewers agreed to that decision. Let me explain.

Consider the situation when you have 6 buttons, which can be enabled or disabled in various combinations depending on user selection of a text field elsewhere in the application window. My task was to write a Jemmy unit test and check if these buttons are enabled/disabled in proper combination after specific text field selection. So I created a method with 6 boolean parameters which corresponded to the enable/disable state of each button. By calling this one method I could easily test all text field selection possibilities.

Basically I broke 2 two Uncle Bob (a.k.a Robert C. Martin) rules: I used boolean parameter and I used more than 3 parameters. However in that particular situation this solution work quite well, yet I am still not sure if that was a best decision.

Fataho
  • 57
0

Data vs logic

On a big picture (and oversimplified) scale, code can be segregated into two categories: data and logical flow. Many people can add additional ones they think is just as important but they're irrelevant for the answer at hand.

You're right that booleans for logical flow are bad practice. I would slightly alter that interpretation and say that it's bad practice for a public API (what you do internally matters less), but that's maybe a different discussion for a different day.

Booleans as data

By excluding booleans for logical flow, we haven't actually excluded booleans that function as data.

For example, while you might expect an update method to look like this:

public void Update(User u) { ... }

maybe you want to limit which fields of the user can be updated (e.g. not the username, but the user's first/last name can be changed), which leads you to:

public void UpdateUser(string firstName, string lastName)

It's not too farfetched to think of examples where a boolean field can be changed:

public void UpdateUser(string firstName, string lastName, bool isAlive)

And this is a basic example of why boolean parameters do exist. Some data simply has an innate binary nature, and therefore it is best represented by a boolean.

Let's ignore the "dead people can't come back alive" argument and say that we allow for fixing bad data (we thought the person was dead but we were wrong). I picked living/dead because we can all agree that this is a binary value. Other options exist but I picked the one with the most commonly agreed upon consensus.

No passing allowed?

The method should use the boolean value itself and not simply pass it through to some other method.

I find this a bit too restrictive of a requirement. In effect, the above passes the boolean through many layers down to the DAL. It's eventually translated into e.g. a SQL statement, but it has passed through many layers before it gets to that stage.

Your current phrasing excludes this as a valid answer, but I very much disagree that this particular example is invalid for the core of your question.

Booleans should never change logical flow?

I also find the "no logical flow repercussions from booleans" argument to be excessively broad and restrictive. Taken to heart, you're effectively suggesting that the if statement should have never existed.

I can also think of cases where the boolean causes logical flow variations yet still is relevant, e.g. if the backend uses separate external services for handling living/deceased people.

Consider an application which connects to external services (e.g. government registry: one for the living, one for the deceased), where you do not want to expose to your user that different services are being used. "Unbooleaning" a method leads to something along the lines of

public void DoActionForDeadPerson(...)

public void DoActionForLivingPerson(...)

(Obviously, better names are needed in reality)

But this requires the consumer (i.e. the user of your backend service) to know that there is separate handling for living/deceased people, and this may be considered a leaking abstraction in certain scenarios.

It's perfectly reasonable for your application to specifically hide that fact that there are separate repositories. For example, maybe the living/deceased resource split happened after your application went live (it used to be the same resource) and you're trying to implement it without affecting your public API.

Another example

If you can only think of an example with more than one parameter, that's OK too.

While I think there's no real reason to differentiate between methods with only a boolean parameter and methods with multiple parameters (one of which is a boolean), I'll humor you and give you an additional example of a function with only a boolean parameter:

public void SetUserFieldsReadonly(bool isReadonly)
{
    txtFirstName.IsReadonly = isReadonly;
    txtLastName.IsReadonly = isReadonly;
    txtUserName.IsReadonly = isReadonly;
}

Note that in this case, isReadonly again acts as a data-boolean as opposed to a logical-flow-boolean. It's the same underlying principle as the previous example.

Whether you consider the boolean "passed" on is very arguable. While passing it to a submethod obviously counts as passing it on, does setting a property count too? I think this is highly subjective and liable to opinionated feedback.

Can you separate this into a SetReadonly() and SetEditable()? Sure. But it's unnecessary bloat, in my honest opinion. It's copy/paste and whenever you change one method, you're obviously also going to have to change the other method, so it does not pass the DRY test.

But I still agree with the orignal intention of the "no logical flow" rule

As a basic example of boolean usage where I do agree with you that it should not happen:

public void AddName(string name, bool alsoAddLowerCaseName)
{
    _myList.Add(name);

    if(alsoAddLowerCaseName)
        _myList.Add(name.ToLower());
}

It would be much better by letting the consumer call the Add method twice.

string name = "Robert";

AddName(name);
AddName(name.ToLower());

The consumer retains the same control (choosing whether to add the lower case name or not) but it does not require you to keep changing the method for new possibilities (e.g. upper case, reversed string, HTML encoded string, ...)

I believe that these cases are the core concern of your "no logical flow booleans" argument and I do agree with you there.

Flater
  • 58,824