tags:

views:

321

answers:

4

Surprisingly the code bellow will not succeed.

int? n1 = null;
int? n2 = null;
Assert.IsTrue(n1 <= n2);  // Fails here

Do you know why?

+3  A: 

Either this is a typo and you meant "==" not "<=" or you misunderstand how nulls work.

In almost all languages (including c#) the only default legal operation on null is to check if something else is equal to it (in .Net == is by default reference equality).

<= and >= are not meaningful (as they would have very strange behaviour if they did)

Some languages (SQL being possibly the most well known) disallow the use of 'standard' equality operators to make this even more clear. in SQL null == null is NOT true, and a compliant server will refuse queries where you attempt to do this via a literal.

C# takes the same route as it's heritage (C style imperative languages) where the test for a null value is based on testing that the bits in it are zero (things get somewhat more complex but fundamentally that's what is happening). As such only reference types can truly be null (Nullable<T> has a lot of magic behind the scenes to make it look like it is but actually under the hood it isn't null). This means that the reference equality semantics follow nicely into null semantics, thus the == null is allowed.

Other languages implement null in a different fashion (for example SQL where anything can be made null thus the 'nullness' of something must be stored outside of it (much like Nullable). This means that the conventional use of equality need not be the primary concern and null can be truly special rather than a special case of certain types. For further information on the specialness of null take a look at This question has a list of such languages

Most reference types do not define a >= or <= operator so there is little problem in practice with the disconnect between == and <= (where normally if something is true for == it would be true for <= and >= as well).

ShuggyCoUk
Where this gets a bit confusing is C# vs. SQL. In programming languages like C#, null == null. But in SQL, nothing is true - NULL=NULL, NULL!=NULL, etc.
n8wrl
I want to assure you that this is not a typo. I meant "<=".
Vadim
Yes. Null is 'special'. http://stackoverflow.com/questions/75267/in-how-many-languages-is-null-not-equal-to-anything-not-even-null/75314#75314
Jonathan
Good points on the even tighter specialness constrains in many languages - integrating into answer...
ShuggyCoUk
A: 

Nullable types are wrapped into a System.Nullable object, so you don't compare the int value, you compare the reference. To compare the values, you need to make it like that:

Assert.IsTrue(n1.Value <= n2.Value);

I wrote a bit about nullable on my blog.

Edit: But in your case n1 and n2 is null, so you can't even compare the values.

Enyra
How is this better? It just throws a 'NullReferenceException'...
Jonathan
It depends what you want to do, if one of these references is null. Let me assume null is also not valid, so it would look like this:Assert.IsTrue(n1 != null In my example it does not throw an exception if one of these references are null, because the condition is not checked entirely since it is false anyway.
Enyra
+4  A: 

You can try this:

int? n1 = null;
int? n2 = null;

// Test for equality
Assert.IsTrue((n1.HasValue && n2.HasValue && n1.Value == n2.Value) || (!n1.HasValue && !n2.HasValue));

// Test for less than or equal to
Assert.IsTrue(n1.HasValue && n2.HasValue && n1.Value <= n2.Value);
Mark Ingram
The original test was: n1.Value <= n2.Value
Winston Smith
Updated the code. Thanks.
Mark Ingram
+3  A: 

Using boolean logic with null nullable values in C# (and VB.Net) often times defies logic. I find the best way to make sense of it is to remember that "null is not a value". Because null is not a value you cannot do any operations on it. Hence things like "1 > null" and "1 < null" are both true.

Here is a detailed guide: http://msdn.microsoft.com/en-us/library/2cf62fcy.aspx

If you do want to treat null as a value then you could use the GetValueOrDefaultMethod() to equate null with the default value. For example

Assert.IsTrue(n1.GetValueOrDefault() <= n2.GetValueOrDefault());  // True

This is a bit verbose but it will get the job done.

JaredPar