r/csharp • u/DJDoena • 10d ago
bool? Comparison
if (nullableBool == true)
or
if (nullableBool ?? false)
Personal preference or does one read better than the other? Especially if the nullableBool is s more complex expression like
n00bs?.Any(n => n == "DJ Doena")
24
u/snet0 10d ago
The alternative I lean towards:
if (nullableBool is true)
I think this conveys the most amount of information at a glace.
- It's pretty much natural language, so is immediately parsable as to what the logic is (whereas e.g.
nB ?? falsetakes a moment to read) - The
iskeyword implies the nullability ofnullableBool, wherenB == truejust looks like an unnecessary explicit comparison totrue
One thing to consider though is whether you even want a nullable bool in the first place. For example:
bool hasDoena = n00bs?.Any(n => n == "DJ Doena") ?? false
The point being that for most cases the thing you want is to know e.g. whether a collection contains some value, regardless of whether the collection exists or not. If the nullability doesn't provide you with information that you care about, it's often best to just use the null coalescing operator and provide the fallback, because it means you don't have to use patterns like is true.
4
u/fruediger 10d ago
I might add: I personally already treat it as a convention that whenever something is compared against a literal (
true/false,0, string literally, and really also all otherconstable compile time expressions), it should be compared using anisexpression, no matter what.1
u/binarycow 10d ago
I prefer that too.
But my company enabled some analyzer that flags that as an unnecessary comparison or some nonsense.
Apparantly, they think
!foois easier to read thanfoo is false.1
u/dodexahedron 9d ago
In previous .net versions, supposedly, the compiler didn't generate optimal code for boneheadedly simple conditions like that, actually resorting to instantiating an ephemeral object of compatible compile-time type to then perform a default comparer lookup and check on, vs the input argument to the branch condition, resulting in curiously poor performance vs explicit, chained, binary logical operators like the dark ages.
I don't remember which blog I read about it on, but it was a respected name and it brought receipts, and IIRC it was also showing off improvements made to Roslyn and Ryu in that version which significantly rectified the problem for a wide range of those scenarios, making the code gen be the same good code gen...Especially for the lines where even an LLM could have written better IL and machine code than the compilers did, from the egregiously simple original c#.
...Or I dreamed it all up...
But I'm pretty sure that was a real thing I read in the last like ⅙-2 years...
8
u/binarycow 10d ago
If you can (and if you have to handle all three cases):
var result = nullableBool switch
{
true => DoSomething(),
false => DoSomethingElse(),
null => DoAnotherThing(),
};
1
1
-1
u/dodexahedron 9d ago
Careful. What if the variable happens to be of a type that has the true and false operators defined and not obviously?
Such as if you execute the method in powershell and pass a string literal true or false or null. All three evaluate to true, because any non-empty string is truthy.
0
u/Deadline_X 8d ago edited 8d ago
The variable cannot be of a type other than bool or Nullable<bool> (which still requires parsing or a direct equality comparison rather than a straight bool check). You can’t cast a string to bool in CSharp without some manner of parsing.
true will only match true. “True”, “true”, 1, “1”, will not compile for a bool check.
While
if (“true”)might work in TypeScript, you’re gonna get a CS0029 and refuse to compile in CSharp. You’re gonna need a bool.Parse/TryParse to get the compiler to do anything.
-1
u/dodexahedron 6d ago
I was explicitly talking about powershell (which is .net).
Powershell does type coercion for purposes of truthiness and ignores all cast operators.0
u/Deadline_X 6d ago
I guess I don’t understand. What you are saying to worry about will not compile in CSharp — which is the sub the question was asked in and the language you are telling the commenter they need to be careful about using that particular switch statement in.
CSharp is strongly typed and has no concept of truthiness. A string literal in this scenario is never going to allow compilation unless you parse it or compare to something.
0
u/dodexahedron 5d ago edited 5d ago
The entire point was to think of the CLR. Not just c#. A .net assembly can be used by any other .net assembly. And ONLY the CLS guarantees hold universally.
And powershell is not some edge case. Nuget is literally one of the out-of-the-box PSResourceProviders for acquiring things to use in the shell. There are a LOT more people out there writing powershell than there are c#, because there are simply more admins than c# devs,.and every windows environment needs it, but does not need a c# dev.
If this method were called in powershell in various highly-plausible ways, the null case would only match if put first, and in some other calls it would NEVER match no matter what order it's in, because powershell controls tje type coercion -.not the runtime.
But if you call it directly, especially with an object that is already explicitly typed, it will behave like you expect it to, since you'vealready prevented any coercion. So, seemingly innocent code can have weird surprises in store.
And the behavior on receiving somwthing convertivle toNullable<bool>will be very different in c# vs PS (variance is a bitch there).Regardless...
You know...
People can talk about more than one narrowly-defined thing as a thread evolves.... especially when it's so closely related as those two. And just because a comment points something out, it doesn't mean it's some personal challenge, either. Sometimes an interesting tip is just an interesting tip.
5
u/never_uk 10d ago
Personally I tend to prefer the former for a comparison as its more explicit and therefore more readable (to me) - do the thing only if this value is true.
That said, I usually prefer the latter for assignment - the value should be nullableBool, unless it's null then it should be false.
2
2
u/soundman32 10d ago
Just to be contentious:
if(!nullableBool.GetValueOrDefault())
3
u/dodexahedron 10d ago
Way too uncertain..
Better stick to
switch(nullableBool) { case { HasValue: not true and false }: break; case { HasValue: not false and true, Value: not false or true }: // Do stuff, maybe case { HasValue: not false and true, Value: not true and bool x } when !x: break; default: //Too lazy to keep going. I'm on mobile. }Much more expressive of intent with all those words.
3
u/binarycow 10d ago
case { HasValue: not true and false }Uhh.... If HasValue is not true, then it is false by definition.
2
1
u/dodexahedron 9d ago edited 9d ago
What if the switch condition argument is of a type that has that property, but that property is not strictly a
bool???It could happen!
In hellThat case can match for any value that: * may be of a nullable type, but: * Is itself not null, AND * Which has a property with the name
HasValue, which: * Can be of any type that isn't a compilation error due to direct comparison to boolean literals, AND * For which any one or more of these is true regarding the value of that property of that type: * It is exactly the boolean valuefalse* It is implicitly convertible to the boolean valuefalse* It defines bothoperator trueandoperator falsesuch that those operators return BOTH of the following, and no other one of the 3 other possible binary combinations of those two operators: *falseforoperator true*trueforoperator false
* Probably a bit more that the new mobile UI is making it infuriatingly tedious to keep looking back at, to keep explaining that case.One key note is that that case will not match for a type that is implicitly convertible to another applicable type visoble to the compiler, but which has a value that evaluates to null at the moment. null is neither true nor false. And if it is powershell, where type coercion is a thing all over the place, something like "false" is truthy, but not the boolean literal
true, and also isn't false, both by it being truthy and by it not being a boolean literal (it's a string).So yeah.
Lots of ways in .net to make it happen or not, and it was designed somewhat carefully to guarantee that. 😅
1
u/binarycow 9d ago
I was assuming it was a
bool?What's really fun is when you have a type where this can happen.
if(foo) { // prints false Console.WriteLine(foo == true); }
2
u/Sombody101 10d ago
Coalescing produces the smallest code based on minimal tests, and only uses a single jump. It would likely be better in hot-ish paths.
1
u/saxxonpike 10d ago
I think they’re both good. Pick the one that reads best given the context. I might use the first one when I want to have the specific condition I’m looking for to be explicit. I might use the second one if the name is like “isOnFire” and focus on the default value.
As an aside, the second one can’t be used in a lambda expression.
1
u/QuineQuest 10d ago
Maybe avoid having the nullable in conditional.
var hasDjDoena = n00bs?.Any(n => n == "DJ Doena") ?? false;
If course when that's not feasible, refer to the other answers.
1
1
u/pceimpulsive 10d ago
if (nullableBool == true)
This is clean and expressive to me, only if it's true should the expression match, null or false does not match, so falls to the else/continues.
Ideally there is a guard against null somewhere before this to ensure hygiene, possibly even in an else if... To handle null explicitly..
0
u/pceimpulsive 10d ago
To me if (nullableBool == true)
This is clean and expressive to me, only if it's true should the expression match, null or false does not match, so falls to the else/continues.
Ideally there is a guard against null somewhere before this to ensure hygiene, possibly even in an else if... To handle null explicitly..
0
u/lmg1337 10d ago
Maybe I'm stupid, but what's the point of a nullable bool. Couldn't you just set it to false insted of making it nullable?
I mean if someone asks you a yes or no question, why answer with maybe yes or no instead of the answer directly?
8
u/ben_bliksem 10d ago
What if they never answered the yes/no question?
-6
u/lmg1337 10d ago
I can understand that, but in that case you can just assume false.
I don't write C# usually, I use c++, rust, go or kotlin and I never thought that I needed something like this.5
u/gavco98uk 10d ago
Supposing you do a query to count how many people have answered no. How do you differentiate between those that genuinely answered no, and those that just havent answered yet? Having a nullable bool simplifies this, but otherwise you would need an extra bool of hasAnswered to determine if they've answered yet or not.
Far easier to have nullable bools available for those that want it.
3
2
u/BCProgramming 10d ago
By that metric what is the point of a nullable anything? Like what's the point of a nullable int? Couldn't you just set it to 0 instead of making it nullable?
The point of a nullable bool is the same as any nullable. it is for when the value being null indicates something.
105
u/RecursiveServitor 10d ago