views:

1481

answers:

19

I just found a bug caused by a boolean parameter... the caller thought it was controlling one thing but it was really controlling something else. So do boolean parameters smell in general? Personally, I don't feel comfortable when I see them. I mean:

DoSomething(false);

What the heck am I supposed to think when I read something like that?!

+4  A: 

Not at all.

Sometimes you need a method to perform some operation in one fashion or another depending on the situation. And when in your software you need one way or another is usually clear.

Also when you refactor software you need to extend some method behavior. In order not to break the old code you just add one more parameter to the method signature and then add an "old" shorter version of the method calling the long one with some parameter set to a fixed value.

For example:

You have somewhere in your code:

public void SendOrder (Guid customerID, ShipmentOptions options);

It also sends automatically a confirmation email.

Now you decide to add, say, an automated system order feature where you do not wish the emails to be sent. And you also wish to keep the old code intact. So you extend it:

public void SendOrder (Guid customerID, ShipmentOptions options,
                       bool sendConfirmationEmail);

and add a short version for backwards compatibility:

public void SendOrder (Guid customerID, ShipmentOptions options)
{
    public void SendOrder (customerID, options, true);
}

So boolean parameters are just fine.

Developer Art
Your code actually demonstrates the problem pretty well - looking at a call to `SendOrder`, it is immediately obvious what `customerID` and `options` mean, but the meaning of `true` is unclear and requires actually looking at parameter name.
Pavel Minaev
+34  A: 

What the heck am I supposed to think when I read something like that?!

I'd say pretty much the same thing you'd think if you saw DoSomething(5). If you aren't sure what the API of a given function is, then it's best to look at the function definition. There's nothing wrong with a boolean parameter any more than there's something wrong with a parameter of any other type. If the caller doesn't know the API, no amount of data type gymnastics will help that.

Adam Robinson
I like putting comments on the function declaration and definition to explain any such parameters, myself.
David Thornley
Agreed - and some languages make it more readable with keyword parameters, e.g. DoSomething(:allowCached => false)
Harold L
RTFM is of course a good idea. But some of us also believe that APIs should to a certain extent be self-documenting, and boolean parameters are a known problem in that area.
anon
I hate the SO comment mechanism so much! I meant to say that the API should be self-documenting, but so should the API call.
anon
@Neil: I agree that the call should be self documenting, but I also think that you shouldn't choose another data type *altogether* just because a boolean's purpose might not be immediately obvious.
Adam Robinson
@Downvoter: Care to post what it is you don't like about my answer?
Adam Robinson
@Adam Robinson You're always choosing one data-type over another. Choosing a bool as the parameter type by definition means that you have chosen another data type altogether (you've chosen not to use int, long, double, string, enums, etc.). (I am not the downvoter)
AaronSieb
@Aaron: I'm not sure what you mean. Of course choosing a boolean over, say, and int is a data type choice. What I mean is that the clarity of what the call will look like should not be a determining factor in that choice. The nature of the data should decide.
Adam Robinson
@Adam Robinson But an enumerated type is no worse a representation for a two-state switch than a boolean is. An enum can represent exactly two values (just like a boolean) if that's what's required.
AaronSieb
@Aaron: Sure it can. An enum can also represent ONE value, though there's not a lot of sense in that. You're correct if you're implying that a boolean is not the NECESSARY choice when there are two values, as the values themselves may not be in an appropriate format. Specifying input or output, for example, doesn't really fit into a true/false format, but something like Write/DontOverwrite is well suited to a boolean. I'm not sure what you're getting at here.
Adam Robinson
@Aaron: And as an aside, an enumerated type is actually worse, as there is no range checking (in some languages, C# and Vb.NET for example), so what's intended to represent two values may indeed represent more and require a runtime failure, while a boolean can literally support only two values, meaning that you can depend on that state implicitly.
Adam Robinson
My point is that that an enum is no worse than a boolean value in almost all cases, AND more readable. The ability to assign an arbitrary integer to an enum value in .NET is an excellent point (although doing so is definitely bad practice). This is all in response to your comment @Neil where you state that choosing a boolean whose purpose is not immediately clear is preferable to "choosing another data type altogether."
AaronSieb
@Aaron: Then we disagree. There's clearly a point to the boolean data type, and I don't think that it's some sort of antiquated structure that should be abandoned for the use of an enum in "almost all cases". There are cases where it should and should not be used, as with any data type (including enums). What I said--and I stand by it--is that the nature of the data is what should determine the choice of data type, not the readability, especially in an environment when it's very easy to view the function declaration, like Visual Studio.
Adam Robinson
I'm not trying to say that booleans should be done away with, only that readability should be a factor in determining the data type (and that boolean values are often, but not always, unclear as parameters). If a boolean is used in an instance where it's purpose is not immediately clear, then it may have been the wrong choice of data type for the variable.
AaronSieb
+8  A: 

As per here:

Do not use Booleans unless you are absolutely sure there will never be a need for more than two values.

Otávio Décio
And be sure not to use an integer of you need to represent a fraction. And don't use any other data type that can't hold the data that it needs to represent...
Adam Robinson
+3  A: 

Boolean parameters are fine, especially when in modern IDEs you can hover over them and get help on what the parameter is for.

If you are using the same bool in multiple methods, consider replacing it with an enum. This has several benefits:

  • Code is much more readable
  • It's harder to make a mistake and pass in the wrong value
  • It's much easier to refactor later if you realise you need a third option!
  • All functions that take the value have a common, consistent API
Jason Williams
+7  A: 

It works in situations where the function name is clear. In your example the confusion is more from what is "something".

If the function call was ShowWindow(true), it's pretty clear what is going on.

However, if a method takes multiple parameters, and you have a boolean being used as a flag then I can see confusion. ShowWindow(123, 321, x, y, true) is not immediately clear, and an enumeration instead of a boolean would make it legible: ShowWindow(123, 321, x, y, POSITION.ONTOP).

Mike
Yes, in my (buggy) situation, the boolean was actually one of several parameters.
JoelFan
A: 

From an OOP perspective, it is nice for the object state to handle that but from a simplicity perspective, it's just two states you have to worry about and test. I would say it's a smell but not one worth refactoring away as a high priority. The code would really start to smell if you were using a switch statement.

Austin Salonen
+22  A: 

Boolean parameters don't smell, but they are often misused.

A parameter should be a boolean if it's obvious that the two "options" are "True" and "False". For example, for a method like this, boolean is perfect:

SetVisibility(true)

However, if the meaning does not explicitly mean true or false, I think an enum is nearly always a better option. This also opens up the possibility for more than 2 meanings, which is very valuable.

Reed Copsey
kind of like how in Silverlight/WPF Visibility has 3 values
Jimmy
I prefer SetVisibility(visible) and SetVisibility(invisible).
BoltBait
Heh, which I always thought was a very odd design choice, but they decided to not make it a boolean for that reason. To me "Collapsed" has nothing to do with visibility, and I wish it was 2 properties.
Reed Copsey
yeah, and that way its possible have visible elements that don't take up space, so I can stop wrapping things in extraneous wrappers just to get them to overlap.
Jimmy
It should be SetVisibility() and SetInvisibility(). ;-)
Nosredna
Or just SetVisible(true), SetVisible(false)With SetVisible( bool visible ) as the signature.
Nailer
I hate the Set... pattern. That's what properties are for in the first place.
Reed Copsey
SetVisibility(visible) and SetVisibility(invisible) sounds to me like SetGreenApple(Green) and SetGreenApple(Red). Something is Visible or Invisible not InVisibleVisible... (Semantics)
Caspar Kleijne
A: 

In a language like Objective-C, this isn't really a problem. Any method call contains the name of the parameters, and so it becomes very clear what is supposed to happen; e.g.:

[someObject doSomething: something animated: YES];
Jacob H. Hansen
+10  A: 

The problem (in this particular example) is not with the boolean parameter itself, but with the name of the method that contains it

BlackTigerX
It's both. Some names make sense with a boolean parameter, while others are ambiguous. We should prefer the former, of course, but also be willing to use an enum if that's what it takes to be clear.
Steven Sudit
(To be clear, I do agree that the name is a part of it, so +1)
Steven Sudit
+6  A: 

Boolean flags are iffy. They imply the routine uses logical (flag) cohesion. That's a lower level of cohesion than is ideal. The only worse kind is "Coincidental" (basicly no cohesion). You should generally try to avoid it if you can. The typical fix is to split the routine into two. But sometimes it is the simplest and clearest way to do things.

What the heck am I supposed to think when I read something like that?!

Well, this is why languages should have named parameters. In Ada the code could read:

DoSomething (WithKetchup => false)

Languages which allow named parameters in the calls include: Ada, Python, Ruby and Javascript.

T.E.D.
In some languages you can pass in an object you build on the fly. JavaScript:doSomething({withKetchup : true , withMustard : false , withMayo : false});
Nosredna
I edited this answer to include some other languages apart from Ada that support this. (Although Ada was the first language I saw that did this.) I am just trying to prevent the same answer being posted repeatedly, with the only difference between the language name.
Oddthinking
Good addition. Thanks.
T.E.D.
+1  A: 

I use this C++ convention:

DoSomething (false /* WithKetchup */);
AK
The nice thing about Ada is that this "convention" is checked by the compiler. Eg: If you mess up the order, it makes sure the right actual parameter goes to the right formal.
T.E.D.
OK - until the next maintenance programmer doesn't bother updating the comments...
Simon
+2  A: 

I think there is no problem with boolean params, but it can be troublesome if they are used carelessly (as it seems in your situation).

  • If you have a signature like: createAnimation(boolean isTemp), the best choice would be to separate the method into 2. createAnimation() and createTempAnimation().

  • If you have an "one way method" like: setVisible(true), a boolean would be just fine, since the name of the method is readable. Anyway, if you have access to change the code, modify it like that to keep it more readable. But if you don't have you should just read the function definition

Diego Dias
+3  A: 

This guy will likely tell you that too many parameters and especially boolean parameters are definite code smells. I highly recommend his book, Clean Code.

The problem with APIs like

SendOrder( order, true );

is that they tend to rot and become something like:

SendOrder( order, false, true, 0, null, etc );
azheglov
the code I debugged was like your 2nd ("rotten") example.
JoelFan
+3  A: 

In Ruby, I try to use options hashes as often as possible.

do_something(:with_ketchup => true, :with_mustard => false)

You can use booleans, and you know exactly what they mean.

Matt Grande
+1  A: 

for loops, while loops, do loops, if/then/else statements, C&C++ ternary ?: operator all use boolean values implicitly.

Your example is one of bad code (the function name gives no indication of what it does so what does false indicate?), but not demonstrative of anything in particular about boolean variable.

I think your question is like those we get about pointers: "I found a bug with use of a pointer, so are pointers bad?". Seems to me like the tradesman blaming his tools.

+2  A: 

But it seems in c & c++, one has to agree that (in cases unlike setVisible(bool) below) they hinder readability when passed as true and false

It is more work for the interface designer but

typedef enum {PLAIN,KETCHUP} condiments; 
burger makeBurger(condiments);

.....

burger mine = makeBurger(PLAIN);
burger yours= makeBurger(KETCHUP);

enforces an increased level of readability at the invokation site. And since the interface is done infrequently compared to invokations(programmers eat a lot of burgers!) why not do the interface this way.

So to me the the problem really is allowing the caller to not document the meaning of the call when there is a not immediately evident meaning.

Documentation at the invokation site may be enforced by coding standards,a bit more carefully designed interface, or the language.

pgast
i like more than one condiment
Jim
"no coke, pepsi" - John Belushi
pgast
A: 

I agree with other posters, it's not the boolean value that's the problem, it's the lack of context for the hard-coded constant.

One thing I did recently in an embedded C++ progam when calling a function in my RTOS that takes a boolean parameter is to say what the param is in a C-style comment:

QueueMessage(/*from ISR*/false);

or

QueueMessage(/*from ISR*/true);

Each line of code would be called either from an interrupt service routine or not from an interrupt service routine, so no variable was needed, but it left a reader a little confused as to what the param was doing.

Back in the day in Ada we could use named parameters:

MyFunc(Param1Name => p1, Param2Name => p2);

and it was very clear what each parameter was. Especially nice was that you could list the params in any order, or leave out any number of default parameters. Too bad more languages don't do that.

KeyserSoze
A: 
DoSomething(false);

Is a great example of non-self documenting code.

Lets assume that DoSomething, when it is passed false, does a "Dry run" (using PHP here)

define('DRY_RUN',false);
DoSomething(DRY_RUN);

is a lot more readable !

So, yes, they potentially are code smells, except maybe in the case of :-

setVisible(true);

or similar

Mez
A: 

In languages with weak typing (Perl, PHP, Javascript, Ruby), I like to pass strings to boolean parameters to document them (if true, that is):

$x = send_mail ($addr, $message, "log", "require_reciept");

Its not a great convention, but better than:

$x = send_mail ($addr, $message, true, true);
Paul Biggar