Asad
Asad

Reputation: 21928

What is the use of Nullable<bool> type?

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

Upvotes: 19

Views: 22863

Answers (15)

Matt Cullinan
Matt Cullinan

Reputation: 108

If you’re about to use a Nullable bool, I would consider using an Enum or other data structure instead. It may help you avoid mistakes when the meaning of NULL is not known.

Recently, I mishandled a Nullable bool. I won’t go into the details of the mistake, but lets just say it was bad enough to require a full rollback. I began to wonder how practical it is to use in most applications. (In part in an attempt to hold on to my broken pride as a result of the stupid mistake 🙂 )

Then, I came across this post and Lee's accepted answer.

This seems to make sense, but the more time I spend with it, the answer becomes FALSE in practice instead of NULL. NULL is just too fuzzy.

Before answering this question one would have to assign a very specific meaning to NULL. Does NULL mean there was an error in the calculation? What if there is an error in the calculation before it is determined that there are only two children? (I would also argue that if there are indeed only two children, this could be handled before the question was posed to the program.)

Because we do not know what NULL means and because it is most definitely not TRUE (because, how could it be?) the BEST answer is FALSE.

Also, if this question indeed returns NULL, we’ve introduced a new definition to the domain. What is the scope of this definition?

So it would appear that TRUE or FALSE states represent a certainty regarding an outcome. NULL can be conceived of in at least three different states. For example, the statement “Thomas went to the bar last night.”

TRUE – Yes, Thomas went to the bar. (likeliest answer if you knew Thomas) FALSE – No, Thomas did not go to the bar. NULL – Huh? Knowable – Something went wrong in the first calculation. E.g. you asked Thomas the question but sneezed while he replied , rendering you deaf momentarily. Simply asking him again will get you the answer.

Unknowable – The bar burned down and Thomas skipped town. There is no realistic way of getting the answer. (Please don’t poke holes in this, but I know you will)

Not applicable – See the example above regarding the three children, but, bars and Thomases instead.

What does NULL mean here? Determining what NULL means must be performed on a case by case basis. This is why I believe it is often better to use an Enum or other structure as it more gracefully exposes the intention behind a non-binary return value.

Upvotes: 1

Michael Stum
Michael Stum

Reputation: 180944

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.

Upvotes: 2

Aaronaught
Aaronaught

Reputation: 122644

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.

Upvotes: 17

Tomas Petricek
Tomas Petricek

Reputation: 243051

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.

Upvotes: 0

Igor Zevaka
Igor Zevaka

Reputation: 76510

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)

Upvotes: 0

jason
jason

Reputation: 241641

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 ints? 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.

Upvotes: 0

George Handlin
George Handlin

Reputation: 143

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.

Upvotes: 6

John Knoeller
John Knoeller

Reputation: 34148

a null value means

  • I don't know.
  • Insufficient data at this time
  • The state of the cat before the box is opened
  • I haven't made up my mind yet
  • Profit

a null value means Mu

Upvotes: 2

delete
delete

Reputation:

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.

Upvotes: 0

caesay
caesay

Reputation: 17213

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.

Upvotes: 2

ChaosPandion
ChaosPandion

Reputation: 78262

Lazy programming!

public bool MyProp
{
    get { return (myProp = myProp ?? GetPropValue()).Value; }
}
private bool? myProp;

Upvotes: 3

Lee
Lee

Reputation: 18747

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.

Upvotes: 42

SQLMenace
SQLMenace

Reputation: 135011

it could be unknown in addition to true or false..in database land a NULL usually means unknown or no value

Upvotes: 3

Bert Lamb
Bert Lamb

Reputation: 2327

being nullable could indicate that the bool has not be set or initialized if that is something your program might need to know

Upvotes: 1

nickf
nickf

Reputation: 546045

a null value means "no value" or "unknown value". In this case, it's not true nor false, but undefined.

See: http://en.wikipedia.org/wiki/Many-valued_logic

Upvotes: 10

Related Questions