I don't get it? What's wrong with returning a bool?
I don't get it? What's wrong with returning a bool?
Contrived example:
bool connectToHost(string hostname, bool useSsl);
First problem: if it fails, why does it fail? Some will be tempted to throw an exception. Better is to return some kind of status.Second problem: you add another version of SSL, now what? If you'd used an enum, it's just another value. If not, you now need to retrofit it.
Better version:
absl::Status connect(string hostname, EncryptionType encType);
People will often make mistakes when a function has 3 or more booleans and put the wrong value in the wrong parameter. With strongly typed arguments, this becomes a compiler error.People will extend booleans to add a third value. In Java, for example:
Optional<Boolean> foo
But it doesn't end there. As I like to say, for when three values for your boolean just aren't enough: @nullable Optional<Boolean> foo
Just start with enums.of anything. This is why non-compatible numeric subtypes are so valuable. Code like "quantity_sold = price" should not compile. You can do the same thing for other types using the same template but IME that's somewhat less common (but does happen: user_name = address!!).
It would be nice to get a variation on std::pair that works in a similar way to Rust's std::result<value, error>, because std::optional is just a dressed up boolean. I did just swipe the std::pair declaration and do that, but having it official would be nice. Especially for the non-throwing version of the standard libraries.
A function with three or more positional parameters in a language that isn’t badly broken (that is, one that supports keyword and/or structured parameters, which pretty much all significant languages do) is, IMO, a code smell. Even if more specific typing and IDE pulling up signatures can makes it less likely to make usage errors, readability is impaired.
This means anytime you operate on a boolean, you must somehow recover its interpretation from somewhere, and the argument is that such recovery is error prone and fragile.
The preferred way, presumably, is then to encode the interpretation directly into the type, so for example you use an enum along with pattern matching, or you write a type that wraps a boolean with some value (like a Maybe/Optional type). In effect anytime you have a boolean, you also carry with it its interpretation side-by-side so you don't need to go figuring out how to recover it.
This article goes into it in more depth:
https://existentialtype.wordpress.com/2011/03/15/boolean-bli...
I personally think it's insightful and useful, but there are also downsides to it as well, for example when you need to operate on multiple booleans, it becomes unergonomic and bloated to deal with pattern matching over multiple enums or having to write out a lot of redundant code instead of operating on boolean operators.
Basically consider these two options:
Option 1: boolean blindness.
bool isEven(int value);
...
if(isEven(x)) {
print("Even");
} else {
print("Odd");
}
Option 2: Enum enum Parity {
EVEN,
ODD
};
Parity getParity(int value);
...
switch(getParity(x)) {
case: Parity::EVEN:
print("Even");
break;
case: Parity::ODD:
print("Odd");
break;
}
You can decide which if the two options above is more appealing to you in terms of reading and writing.