27

Is there any merit to using a nullable bool to store a tri-state value? For example, null == 1st state, false == 2nd state, true == 3rd state?

The overhead is probably higher than using a byte enum, but I'm curious.

Petrus Theron
  • 27,855
  • 36
  • 153
  • 287

10 Answers10

22

You should get a copy of Framework Design Guidelines.

There on page 177 is a chapter Choosing Between Enum and Boolean Parameters.

One of the points there is:

  • DO NOT use Booleans unless you are absolutely sure there will never be a need for more than two values.
Oliver
  • 43,366
  • 8
  • 94
  • 151
17

It's a bit of a subjective question but I'd say no because it would affect readability.

Nick
  • 25,026
  • 7
  • 51
  • 83
9

use ? mark at the end of the type bool which is a struct that contains a nullable bool.

bool? mytristatebool = null;
Jesse
  • 3,522
  • 6
  • 25
  • 40
Sam Saarian
  • 992
  • 10
  • 13
  • C# Guide: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/bool – João Teixeira Apr 17 '20 at 20:38
  • This worked perfect for what I was doing. Thanks for the suggestion, I completely forgot about that. https://gist.github.com/instance-id/ab406a366238a7088978368daf0c87d6 – MostHated Dec 02 '20 at 00:27
5

No

I would recommend to go for Enum as you have already got 3 states in hand now and with scope creep it might increase further. So Enum would be a safe bet and more precise/readable for describing the three states and most important the third state which is neither true nor false.

At the end its more like coding for the eyes who will look latter on to this code and make it meaningful and readable for them

V4Vendetta
  • 37,194
  • 9
  • 78
  • 82
4

I believe it'd an error doing so.

A boolean is a "two-state" type. This is its definition.

In C#, C++, Java or whatever.

If you want to simulate three states, just implement an enumeration instead of reinventing a square wheel!

Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
  • What implementation of SQL? If it's a bit, it can be 0 or 1. – Matías Fidemraizer Mar 16 '11 at 10:26
  • 1
    @Matías: In SQL, the expression `a < b` evaluates to either `TRUE`, `FALSE` or `NULL`. – Marcelo Cantos Mar 16 '11 at 10:26
  • And which is the case of "NULL"? – Matías Fidemraizer Mar 16 '11 at 10:27
  • 3
    @Matías: I'm not sure what you mean. If `a` is `1` and `b` is `NULL`, the expression evaluates to `NULL`. In any case, since this is a C# question, I was being mostly facetious. – Marcelo Cantos Mar 16 '11 at 10:28
  • Ok, this is the point. NULL isn't a boolean. Boolean is "true" or "false", even if SQL evals "NULL" if you want to do "a < NULL" and its result is "NULL". It's like saying, "are you Marcelo?", and your answer is "who knows". You're Marcelo, or you aren't Marcelo, are you? I'm pretty sure that a good SQL query should avoid such evaluation, and it should have "b <> NULL AND a > b". – Matías Fidemraizer Mar 16 '11 at 10:33
  • We're not talking about writing good or bad queries. The simple fact is that, in SQL, boolean expressions can have three different results. Whether or not you call the third possible outcome a boolean or not is neither here nor there. The existence of three-state logic is a long-standing and well-known bugbear in SQL and a known source of an inordinate number of logical problems that plague both users and implementers (e.g., the law of the excluded middle doesn't apply in SQL's boolean logic). – Marcelo Cantos Mar 16 '11 at 10:38
  • Incidentally, the third state is actually called `UNKNOWN` in the SQL standard, but it is pretty much indistinguishable from `NULL` in any practical sense. – Marcelo Cantos Mar 16 '11 at 10:43
  • But you need to assume "NULL" isn't an state of a boolean expression, it's something like a bad approach to avoid an error. You can say JavaScript would have 4-state-booleans: true, false, null and undefined. And this isn't true. It's true/false only too. – Matías Fidemraizer Mar 16 '11 at 10:43
  • From [Wikipedia: Boolean data type](http://en.wikipedia.org/wiki/Boolean_data_type): "For instance the ISO SQL 1999 standard defined a Boolean value as being either true, false, or unknown (SQL null)." – Marcelo Cantos Mar 16 '11 at 10:45
  • I believe you're not following my argument. You can have two scenarios: one is you got a value for the boolean variable, expression or whatever, and the second would be "this boolean doesn't have value". Is "SQL NULL" a state of boolean? NO. It's a VALUE of the BOOLEAN field :D Boolean field can be true, false or null. But a boolean is true or false. If it's null, the meaning is "it's not assigned". – Matías Fidemraizer Mar 16 '11 at 10:50
  • Three-valued logic was a bad idea even when Codd devised it, but SQL screwed it up even more by conflating the `UNKNOWN` truth-value with `NULL`, which signifies the absence of a value. `UNKNOWN` is a distinct truth-value that means, "The test has been carried out, and the answer proved to be UNKNOWN." `NULL` signifies that we don't even have the answer to the test, either because the test hasn't been executed, or because the result has been wiped. SQL doesn't let you distinguish between these two cases, but it still defines them. – Marcelo Cantos Mar 16 '11 at 10:51
  • Well, I believe we're agree at all!! hahaha – Matías Fidemraizer Mar 16 '11 at 10:55
  • To illustrate, consider the following code: `BOOL test; PRINT test; test = (a < b); PRINT test`. In a proper 3VL system, this code would print `NULL` followed by `UNKNOWN`. – Marcelo Cantos Mar 16 '11 at 10:58
  • Understood. By the way, NULL and UNKNOWN aren't boolean states! But we're agree in your explanation :) – Matías Fidemraizer Mar 16 '11 at 11:00
  • @Matías: You're right, I've been loose with my terminology. NULL is a tag that signifies the absence of a value, and UNKNOWN is the third *truth-value* in 3VL. – Marcelo Cantos Mar 16 '11 at 11:05
  • Yeah, that's the point. I believe we're agree, but if asker's goal is "I want three states and this will be done with a nullable boolean in C#", I believe we're both agree in that's absolutely incorrect. – Matías Fidemraizer Mar 16 '11 at 11:10
  • @Marcelo Cantos: Re. "In SQL, the expression a < b evaluates to either TRUE, FALSE or NULL." : In SQL Server, "a (Comparison Operator) b" evaluates to either "TRUE" or "FALSE". If a and/or b are `NULL`, "a (Comparison Operator) b" evaluates to "FALSE". Now, if a and/or b are numeric, "a (Arithmetic Operator) b" evaluates to `NULL`. Btw, SQL Server has no Type that can be assigned a "TRUE" or "FALSE", a "TRUE" or "FALSE" value has to be *converted* to a, respectively, 1 or 0 before assigning to its Bit Type. – Tom May 17 '18 at 21:13
3

If it's a WinForms program, then one possibility would be to use System.Windows.Forms.CheckState. It has values Checked, Indeterminate and Unchecked - which may or may not suit your purposes.

RenniePet
  • 11,420
  • 7
  • 80
  • 106
1

A simpler workaround is to have two boolean variables. One will keep null/not-null and the other will keep true/false

An application of this:

When you are caching a calculation in a boolean property, you need to know if it has been already set or not.

e.g.

// actual variable having true/false
private bool isX = false;
// variable holding wither above is set/not-set i.e. null/not-null
private bool isXSet = false;

public bool IsX
{
   get
   {
      if (isXSet)
      {
         return isX;
      }
      else
      {
         isX = GetX(); // this could be time consuming.
         isXSet = true;
         return isX;
      }
   }
}

This become useful in performance tuning when GetX() above is time consuming and IsX is accessed many times.

Gayan Dasanayake
  • 1,933
  • 2
  • 17
  • 22
0

It depends. Great for a property like 'Has Dog': True, False, or we just don't know.

Chalky
  • 1,624
  • 18
  • 20
0

I would stick to null for unknown or not yet determined. Also you lose the possibility to do math on the values. All in all not a good idea I think

Pleun
  • 8,856
  • 2
  • 30
  • 50
0

I get why people are suggesting not to use this to represent options A, B and C. I would go with an enum for that too.

But bool? is great for representing an actual boolean value that might not be fetched or generated yet. And no, having a separate bool for fetched is not simpler, it's messier. IMHOP

Now if only C# allowed for local static variables so we could make this fully self contained, like so:

bool isSomething{
    get{
        static bool? _isSomething = null;
        if (null == _isSomething){
            _isSomething = goFetchIsSomething();
        }
        return _isSomething == true;
     }
}

But since purists hate readable code the best you can do is this

private bool? _isSomething = null; //Pretty please don't try to use me outside of isSomething
bool isSomething{
    get{
         if (null == this._isSomething){
             this._isSomething = goFetchIsSomething();
         }
         return this._isSomething == true;
    }
}
Leif
  • 19
  • 3