0

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.

  • 2
    Dear Close Voter, I'm asking when a boolean parameter isn't a code smell, if ever. – CJ Dennis Nov 5 '19 at 4:40
  • 8
    I disagree with your first statement. Wouldn't that potentially lead to lots of duplicated code, since (presumably) the two functions would be very similar? With potentially extra conditions to decide which of the two functions to call if the boolean parameter is a variable? – 1201ProgramAlarm Nov 5 '19 at 4:50
  • 2
    Wouldn't a clear case be when the boolean is data? E.g. you need to represent something based on a set of parameters of which one is a boolean. Maybe you want to create a string, save something to the database, etc. Point is, is it is not a concept you are using to flag but data to be used just a as any other parameter, you might just want to keep it one function instead of multiple? – Nanne Nov 5 '19 at 11:12
  • 7
    "Most programmers (including me) believe that ..." -- Rephrase that to "Some programmers ..." and the question is then actually quite good. – Martin Ba Nov 5 '19 at 11:56
  • 2
    Please after getting 6 answers, do not change the question in away that could lead readers to think that the answers were irrelevant. I'd suggest that you put an "Edit" or "Clarification title before the new elements that you've added. – Christophe Nov 5 '19 at 12:54
18

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.

  • I'm afraid I don't understand. I don't use any language that has assert(), and it just sounds like a unit test. In PHPUnit there is assertTrue() and assertFalse(), so even this is split into two methods. And unit tests are special code. I do things in unit tests I would never do in production code because they would be bad practice, yet are good practice in tests. – CJ Dennis Nov 5 '19 at 2:52
  • 1
    The issue has nothing to do with production verses debugging code. It has to do with readability. The reason this works is because there's one argument to remember and there is no else case. This only does what it does when you pass a false. – candied_orange Nov 5 '19 at 3:13
  • Is this for unit tests only? If not, what use case does it have? Can you provide context around your example code? – CJ Dennis Nov 5 '19 at 3:14
  • 2
    This is a brilliant answer. I have expanded this to make it more descriptive. @CJ Dennis, this doesn't need to used in unit test. It could be used in production code for error hanlding – Nachiappan Kumarappan Nov 5 '19 at 10:25
  • 2
    @CJDennis lol, just because you don't use such languages doesn't mean other languages have good use for it, does it? Also: arguing X is bad because X is bad is a logical fallacy. – marstato Nov 5 '19 at 10:58
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.

  • I think most programmers would treat a bit (as in one eighth of a byte) differently from a boolean (a data type), even though a boolean in theory only needs one bit to represent it. In practice, booleans are normally not packed together eight to a byte. And setMarried() could have a counterpart setSingle() which eliminates the need for a boolean. – CJ Dennis Nov 5 '19 at 10:42
  • @CJDennis Yes it could have a counterpart - But you haven't said why it should? Almost all code has at least 1 alternative way of writing it (I would say all code, but absolutes are "almost" never correct!). To me, user.setMarried(true) is just as quick to grok as user.setMarried() & user.setSingle(), and it would depend on the domain language we are using. If my client/users said "A user is single" I would use your option, user.setSingle(). If they said "A user is not married" I would use user.setMarried(false). – Jack Nov 5 '19 at 10:53
  • @CJDennis would it be better? Do you think that copying the status with a.setMarried(b.getMarried()), is worse than if(b.getMaried()) a.setMarried() else a.setSingle() ? when at he same time for a non boolean you’d just stick to the a.setXxx(b.getXxx) ? Wouldn’t handling all the booleans like this not violate the law of demeter ? And if it would be so much better, why wouldn’t you generalize it to other types, for example setBirth(year) would become setBirthyear1970(), setBirthYear1971(),setBirthYear1972(), etc... ? “Most of the programmers” prefer to handle data as data and not as code. – Christophe Nov 5 '19 at 11:18
  • To attempt to sincerely answer your question, I think it's because we as humans don't think about "is Chris married true?" or "is Chris married false?", just "is Chris married?" which gets a yes/no answer (possibly with additional information, "no, but Chris just got engaged!", "not yet", "Chris divorced last year", "this is Chris' third marriage"), not a true/false answer. Whereas we think about "what year was Chris born in?" which gets a numerical answer. – CJ Dennis Nov 5 '19 at 11:34
  • @CJDennis For some systems, the question is just to know whether or not a person is married at the time of the registration, without care for any other variants. In this case the yes/no is a data. Bollean is a legitimate encoding. Coding it as a string "YES"/"NO" could avoid the boolean, but that's my point: do we have to avoid the boolean ? Why shouldn't booleans have the same rights than other types: just because of some prejudice, because sometimes they are used in the wrong way ? Are cars forbidden because some people make accidents with it ? – Christophe Nov 5 '19 at 11:49
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.

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?

  • PHP serialises for me. It takes any constant or parameter, not just booleans. I would never need to write my own serialiser. As for "most programmers believe", it's based on the answers on this very site for multiple questions about boolean parameters. – CJ Dennis Nov 5 '19 at 4:24
  • 3
    Well you asked if there is a use case, and I gave you one. Now you say you wouldn't need that in one specific language - that doesn't make it invalid for all other languages. If you care only about bools in php, add it to the question. Otherwise, I can bring ten more examples, and you can bring ten more languages were those specific examples might not apply. - My impression is that your mind was already made up, and the question is purely rherotic. – Aganju Nov 5 '19 at 5:33
  • 1
    If I'd asked about passing integers, strings, or arrays, etc., the answer would be "it's unlimited". It would be very difficult to write most code in most modern languages without one of the basic types, all except booleans. The use case of serialisation is very niche. Let's say I'm writing a web application. When would I need to write a method that accepts a boolean? What about code to analyse signals from deep space? Etc. I accept that as written my question mightn't express what I want to ask. – CJ Dennis Nov 5 '19 at 5:42
  • 2
    I agree with Aganju, it seems like you've already made your mind up about what the answer is. You're arguing the No true scotsman fallacy. Somebody has to write the serializers of the world. – Blake Nov 5 '19 at 12:59
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

  • I agree that flag parameters are bad and should be refactored by using meaningful method names. You say a boolean will always be a flag. That's the heart of my question. If this statement is true (a boolean is a flag), why must it be? – CJ Dennis Nov 5 '19 at 10:36
  • The thing is that most of the times, the caller knows the value of the flag so it can decide to call callee.methodA() or callee.methodB() indistinctly what makes the code more expressive than passing the boolean to callee.method(bool) which in many cases leads to break the principle of "least astonishment" (we have to look inside the method). Whether there're are not legit cases for flag arguments, if they can be replaced by a better "design" then doesn't matter if they are legit or not. In other words, doesn't matter if you find the Lost Ark, you will not be allowed to open it for longer. – Laiv Nov 5 '19 at 10:52
  • @CJDennis, when you look at the method body, you are receiving a boolean, so it can only flag something as true or false. I don't think there is another way about it. – Nachiappan Kumarappan Nov 5 '19 at 11:01
  • In the calling side if you pass the value "true" or "false" the readability will be compromised. On the other hand if you pass an expression that gets evaluated to a boolean, then the readability is not compromised. – Nachiappan Kumarappan Nov 5 '19 at 11:03
  • arent your good examples actual taking a boolean function parameter? – Ewan Nov 5 '19 at 12:12
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.

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.

  • Probably a better word for "dilemma" would be "alternative". I studied the play A Man for all Seasons in school and I still remember the line "There is no third alternative" because my teacher explained that is has a double meaning, that there were only two choices, and that "alternative" means "the other one", i.e. an alternative is always one of two choices. The only alternative to if is else, although it can be extended with another if. – CJ Dennis Nov 5 '19 at 6:58
  • @CJDennis Indeed, "dilemma" was probably not the most suitable word for what I meant. I replaced it with "alternative" ;-) – Vector Zita Nov 8 '19 at 16:00
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.

  • “No passing allowed” is obviously nonsense. A method has an interface and acts accordingly. How it is implemented is nobody’s business. – gnasher729 Nov 5 '19 at 15:09
  • @gnasher729: To be fair, OP is asking for an example implementation to disprove the "no booleans parameters in the interface" argument. So the implementation is exactly OP's business (at least for the sake of example). – Flater Nov 5 '19 at 15:27

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