a bool variable could hold true or false, while bool? could be null as well.
Why would we need a third value for bool ? If it is not true, what ever it is, it is == false
Can you suggest a scenario where I would fancy a bool? instead.
Thanks
a bool variable could hold true or false, while bool? could be null as well.
Why would we need a third value for bool ? If it is not true, what ever it is, it is == false
Can you suggest a scenario where I would fancy a bool? instead.
Thanks
a null
value means "no value" or "unknown value". In this case, it's not true nor false, but undefined.
being nullable could indicate that the bool has not be set or initialized if that is something your program might need to know
it could be unknown in addition to true or false..in database land a NULL usually means unknown or no value
Something can be true, false or undefined for many reasons. How would one answer "Is your third child a girl?" if one only has two children? Both true and false are incorrect. Null would be appropriate as saying that the comparison doesn't apply.
Lazy programming!
public bool MyProp
{
get { return (myProp = myProp ?? GetPropValue()).Value; }
}
private bool? myProp;
Well I could see it being used as a "Not determined yet" kind of thing, i use bools all the time and sometimes just two values isnt enough!! for instance:
bool? bl;
bl = true; //Yes
bl = false; //No
bl = null; // Not determined, so do nothing
in my opinion its just the third value to a bool.
You'd want to use that to cover the situation of "what if the user doesn't specify neither true nor false?"
It's just a way to cover all possible outcomes.
a null value means
a null value means Mu
It's good for when something hasn't been answered yet - think of a questionnaire. You have a list of y/n questions and only some have been answered. You wouldn't want to post true or false to the database table because the user hasn't answered the question yet.
Let's say that an order has been placed but not shipped yet. What is the value of Order.ShippedDate
?
The old-fashioned way to handle this was to use a magical value like DateTime.MinValue
. There were other ways to solve this problem (for example a wrapper type or an additional bool
flag indicating that the order has not shipped yet). None of these is very satisfactory. What is needed is a uniform way to handle the problem of a missing or unknown value.
So the modern approach is to allow Order.ShippedDate
to take on a value that semantically captures that the order has not shipped yet. That's the role that nullable types play. Semantically you should think of an instance of Nullable<T>
with HasValue
being false
as representing "missing" or "unknown."
Further, databases have long allowed a column to allows null
. For example, you could have an integer-valued column that allows null. How do you interact with such a column from code if you don't allow nullable int
s? Again, you could use the approaches mentioned above but it is so much nicer when the language has a built-in facility for semantically capturing the situation that we are trying to model.
Here is another use case. Think of a hierarchical data structure that has a boolean property. Setting such property on the parent will apply to all of its children, unless those are set explicitly. Think Read only permissions for files and folders in Windows (which DO have a tri-state checkbox).
Parent1(readonly: true, evaluates true)
|-Parent2(readonly: null, evaluates true)
|-Child1(readonly: false, evaluates false)
|-Child2(readonly: null, evaluates true)
|-Parent3(readonly: false, evaluates false)
|-Child1(readonly: false, evaluates false)
|-Child2(readonly: null, evaluates false)
I think the primary motivation (at least it was presented like this :-)) for adding nullable types in C# 2 were databases. In database, any data type can have the NULL
value and when mapping these to C#, this is a problem. Nullable types allow you to deal with this quite elegantly - you can use int?
, bool?
and others. They are used for example in LINQ to SQL.
What does the third value mean for booleans, that of course depends on the application. I guess that typically, it will mean that the value/field is not available.
Various answers discuss the importance of nullable types in general. There is an additional answer for the nullable boolean, specifically. It's hard to understand in C#, but very easy to understand if you look at null-valued logic in any database.
Let's say you're tracking a list or table of Shipments
. A Shipment
has a DeliveryDate
, but of course you don't know this information until long after the shipment has been made, and probably at least a few days after the shipment was actually delivered, when UPS finally gets around to notifying you. So of course the DeliveryDate
is a Nullable<DateTime>
(or DateTime?
).
You want to retrieve a list of all shipments that were delivered during the last week. So you write this:
var deliveredThisWeek = shipments.Where(s =>
s.DeliveryDate >= DateTime.Today.AddDays(-7));
Should shipments with a null
delivery date be included? (The answer is, of course, no.)
OK, so what about this:
var deliveredBeforeThisWeek = shipments.Where(s =>
s.DeliveryDate < DateTime.Today.AddDays(-7));
Should shipments with a null
delivery date be included in these results? The answer is still no.
So now you have a curious situation. You might think that between the two of these queries, you would receive all shipments in the system. A | !A
is always true
, right? Not when you're dealing with nulls.
Even this one fails to get you all the results:
var deliveredAnytime = shipments.Where(s =>
(s.DeliveryDate >= DateTime.Today.AddDays(-7)) ||
(s.DeliveryDate < DateTime.Today.AddDays(-7)));
So how is this possible?
In order to accurately represent this logic, you need a condition that is not true or false. And again, C# is kind of a bad example here because it doesn't implement the logic the way you'd really expect it to. But in SQLese, it makes sense, because:
[DeliveryDate >= BeginningOfWeek] = NULL
[DeliveryDate < BeginningOfWeek] = NULL
Clearly, NULL OR NULL
is still NULL
, not TRUE
. That is how you can correctly say that a shipment was not delivered before the beginning of the week, and was not delivered after. Or, more accurately, we don't know when it was delivered, so we can't safely say that it does match either of those conditions.
But C# is not so consistent. In C#, if the DeliveryDate
is null, then:
(s.DeliveryDate >= beginningOfWeek) == false
(s.DeliveryDate < endOfWeek) == false
Which gets you the right answer for our query above, so you might be tempted to say that regular boolean logic is good enough, except that this one messes it all up:
var deliveredThisWeek = shipments.Where(s =>
!(s.DeliveryDate < DateTime.Today.AddDays(-7));
Aha... now it's giving us back null
delivery dates! This isn't right! And before someone says "@Aaronaught, what are you on about, of course it's right! Those shipments were NOT delivered before last week, so the condition should cover them!", stop and think about it for a second.
The NULL
doesn't actually mean that they weren't delivered. The NULL
means that we don't know when they were delivered. It's possible that a clerk will pick up the confirmation tomorrow, and fill in the DeliveryDate
as two weeks ago, invalidating the data we just picked up. There should not be null instances coming back from that query, and yet there are. If you wrote the same query in SQL, those results would be excluded.
So, why should you care about Nullable<bool>
when C# apparently doesn't? So you can avoid falling into this trap in your own code:
public static bool? IsThisWeek(DateTime? dt)
{
return (dt != null) ? (bool?)(dt.Value > DateTime.Today.AddDays(-7)) : null;
}
var deliveredBeforeThisWeek = shipments.Where(s =>
(!IsThisWeek(s.DeliveryDate) == true));
// Or, the equivalent:
var alsoDeliveredBeforeThisWeek = shipments.Where(s =>
(IsThisWeek(s.DeliveryDate) == false));
This is a bit awkward, but correct. We've written a query that more or less communicates its intent properly, and (bool?)null
does not equate to true
or false
, so we get the right results in both cases.
If you ever need to evaluate a condition where the answer might be "I don't know" - use a bool?
(AKA Nullable<bool>
) as the result.
That way, the caller can decide how to handle an "I don't know" response instead of you simply choosing a default. Anything else means your class is lying.
I used it in a Filter Value. Basically I have a bool field in the database, but I wanted three states: Only return rows where the value is true, only return rows where the value is false, do not filter and return all rows.
Without a nullable bool I would have to use either an enum or a second bool to determine "Filter by this field yes/no" which would add bloat.