I got bit by a C++ type-safety issue today, and I'm wondering if there is a good way to get the compiler to detect this issue at compile time. Consider this example code:
class Bar
{
public:
void Foo(bool arg1 = false, int arg2 = 10, int arg3 = 20)
{
[...]
}
};
int main(int argc, char ** argv)
{
int x = 40, y = 50;
Bar b;
b.Foo(); // correct usage
b.Foo(true, x, y); // correct usage
b.Foo(x, y); // problem: compiles but won't do what the caller expects
}
As shown in the final call to b.Foo(), the issue is that it's easy to forget to supply the first argument, and in that case things go wrong in a way that is not caught by the compiler.
What would be nice is if I could get the compiler to say something like "ERROR, non-boolean value was supplied to a boolean parameter". That would force the developer to examine the code, and if he really wanted to pass in x as a boolean, he'd have to pass in (x!=0) instead.
This seems like a good place to use the "explicit" keyword, but AFAICT that keyword doesn't work for function arguments.
(I realize that this sort of issue could be avoided by not supplying default values for the arguments, but default values can be quite handy)
Boolean params make code harder to change And this just calls for more. Now, chances are high that someone will have to use the function again, with another slightly different behavior. Another parameter will get added. Because it will feel like the simplest thing to do.
Though it is technically correct to use Boolean parameters, it violates the Single Responsibility Principle and functional cohesion that helps to achieve a single, well-defined purpose to the function. It means that based on a Boolean value, the function does two different things.
Flags are not a best practice because they reduce the cohesion of a function. It does more than one thing. Booleans make it hard to understand what a function does based on the call site. Single argument functions and passing an object with named values improves the readability.
You may provide deleted overloads:
class Bar
{
public:
void Foo(bool arg1 = false, int arg2 = 10, int arg3 = 20)
{
[...]
}
template <typename T>
void Foo(T&&, int = 10, int = 20) = delete;
};
As the template method would be an exact match for non bool parameter.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With