## C#/.NET Little Pitfalls: Nullable Math Doesn't Always Add Up

*C# is a wonderful language for modern programming. While everything in C# has a reason and a place, occasionally, there are things that can be confusing for a developer who isn’t aware of what is happening behind the scenes. This is my third post in the Little Pitfalls series where I explore these small pitfalls; the previous Little Pitfall post can be found here.*

In the last Little Wonders post, we talked about the **Nullable **static class (not to be confused with the **Nullable<T>** **struct**) and through that venue discussed some of the issues comparing nullable numeric values** **which evaluate to **null**.

This week we will dive deeper into that discussion and discuss more fully the little pitfall deals of performing math or comparisons on **System.Nullable<T>** wrapped value type that support the arithmetic and/or comparison operator overloads.

### Overview: Nullable value types

Value types in of themselves cannot be **null, **however those same value types can be wrapped in a **System.Nullable<T>** wrapper (which in C# can be declared more simply by adding a ‘**?**’ behind the type) which then allows the variable to be assigned **null. **This allows you to treat a value type as “optional” where it may or may not have a value.

*Note: A null nullable wrapped value type is not the same as a null reference to a reference type. The null nullable value type still has storage for the value type itself, it just has a bool flag indicating whether or not it has an assigned value. More on this in a future C#/.NET Fundamentals post!*

An interesting feature of the **System.Nullable<T>** wrapper type is that you can directly use the operator overloads that are also available in the wrapped type. This is not just relevant for primitive types (like **int, double, long, **etc) but also operator overloads defined on **struct **types.

For example, let’s create just a simple **struct** to represent a fraction (never mind if this should truly be a **struct** or **class **in the grand scheme of things, just buy into it as an example):

1: public struct Fraction

` 2: {`

3: public int Numerator { get; set; }

4: public int Denominator { get; set; }

` 5: `

6: // an operator overload to support + operator.

7: public static Fraction operator +(Fraction first, Fraction second)

` 8: {`

9: // ignore reduction and LCD, just doing brute force

10: return new Fraction

` 11: {`

` 12: Numerator = first.Numerator * second.Denominator`

` 13: + second.Numerator * first.Denominator,`

` 14: Denominator = first.Denominator * second.Denominator`

` 15: };`

` 16: }`

` 17: }`

So, we now defined the **operator +** for our **Fraction** value type. So this means we can add two fractions like:

1: var oneHalf = new Fraction { Numerator = 1, Denominator = 2 };

2: var twoThirds = new Fraction { Numerator = 2, Denominator = 3 };

` 3: `

4: // 1/2 = 3/6, and 2/3 = 4/6, thus 1/2 + 2/3 = 7/6

` 5: var sevenSixths = oneHalf + twoThirds;`

In addition, the **Nullable<T> **wrapper allow any arithmetic and comparison operators of the wrapped type to be performed ** directly** on the wrapper type without explicitly extracting the value (using the

**Value**property):

1: Fraction oneHalf = new Fraction { Numerator = 1, Denominator = 2 };

2: Fraction? huh = null;

` 3: `

4: // this is syntactically correct and thus compiles, but what does it do if huh is null?

` 5: var whatTheHeck = oneHalf + huh;`

So this leads us to our little pitfall. The above code not only compiles, it succeeds at runtime, though perhaps not in the way you may expect. Let’s dig deeper into what we’ll get…

### Pitfall: Math with null yields…?

The first time you see math on a **Nullable<T> **wrapped value type, your first expectation may be to expect some sort of exception to be thrown. Let’s say we’re attempting to perform a volume calculation, and for whatever reason we choose to make our volume generic enough so it can handle a 2d Rectangle or a 3d Rectangular solid:

1: int length = 20;

2: int height = 30;

` 3: `

4: // maybe allow width to be null if 2d or non-null if 3d

5: int? width = null;

` 6: `

7: // calculate the volume

` 8: var volume = length * height * width;`

` 9: `

10: Console.WriteLine("The volume was: " + volume);

Now, you notice that we are performing the mathematical multiplication (**operator ***) against two **int** values and a **int?** value. So, what happens when *width* is **null** as we see in the example above?

Well, you might expect that it would throw an exception, but actually it doesn’t. So then, if it doesn’t throw, does it evaluate to zero (as the coder above may have assumed)? No again, because **null** is undefined, it can’t really evaluate to any particular value – even zero.

So what happens? Well, you know the typical arithmetic type promotions (**int + long = long**, etc.) where basically math between a “smaller” type and a “larger” type promotes the “smaller” type to the “larger” type. Math between **Nullable<T>** wrapped types is somewhat similar in that anytime you have math between a type and a **Nullable<T> **wrapped type, the result will be a **Nullable<T>** wrapped instance of the “larger” type. That is, an expression with **int?** + **long** yields a **long? **result.

So this hints at our answer, which is: when performing math between a type and a **Nullable<T>** wrapped instance of a compatible type, the result is **null!** As they say: the good news is it fails gracefully (doesn’t throw), but the bad news is it fails gracefully (doesn’t throw). Not throwing is s nice in some ways, but in others it can lead to bugs that don’t appear in the trouble spot itself but may have negative effects later in the code.

If you noticed, we used implicit typing in our example above, this may have accidentally helped hide the issue at hand. If we try to type *volume *to an **int, **we get a compiler error that **int?** cannot be converted to **int **which is a big hint that the result of the expression got promoted to an **int? **result.

1: // Compiler error, result of int * int * int? = int?

2: int volume = length * height * width;

` 3: `

4: // Correct, nullable math yields nullable values

5: int? volume = length * height * width;

So keep in mind, any time you do nullable math, the result of the whole operation will be **null** if any part is **null.** The following is logically equivalent to performing the original math:

1: // if a part of the expression is null, the math == null

2: int? volume = width.HasValue

` 3: ? (length * height * width.Value) `

4: : (int?)null;

So be aware that math with a **null** **Nullable<T>** wrapped type yields **null, **so protect your calculations as appropriate, and take appropriate actions if any **Nullable<T> **wrapped value types are **null** (by checking the **HasValue** property or comparing to **null**) before you perform any operations on them.

### Pitfall: Relational operators comparing null yield…?

Comparing a **Nullable<T> **wrapped value type using supported relational operators has a similar effect to the arithmetic operators discussed above, but with a little twist. When you do comparisons between a **Nullable<T> **wrapped type whose value is **null** and a compatible type, the result is **always** **false **for the **>, >=, <, **and **<=** operators. However, it will evaluate as expected for **==** and **!=**.

The **<=** and **>=** can be especially confusing for those who aren’t familiar with nullable logic when you consider this snippet:

1: int? x = null;

2: int? y = null;

` 3: `

4: // you'd think since x == y this would evaluate to true...

5: // but this is actually logically equivalent to:

6: // if (x.HasValue && y.HasValue && x.Value <= y.Value)

7: if (x <= y)

` 8: {`

9: Console.WriteLine("You'd think since x == y this would be true...");

` 10: }`

11: else

` 12: {`

13: Console.WriteLine("But it's not, returns false for <= or >= if either arg null.");

` 14: }`

So, in a nutshell, any **<, >, <=, **or** >=** operators are undefined on **null,** because **null** has no true relative rank (though as we’ve seen in a previous post, the **Nullable.Compare<T>() **method takes a different approach and treats **null** as less than anything). If either of the operands to these operators are **null** then the result is **false** – even if both are **null** in the case of **>=**, and **<=**. But since == and != don’t imply order at all, they are just simple equality or non-equality, comparisons to **null** are well-defined and make sense, and thus will work as expected.

This can bite a bit if you are expecting an exception, but it fails quietly – and in this case even more quietly than **Nullable<T> **wrapped type’s** **exposed arithmetic operators! With the nullable math, we had the **null** result to let us know the result was undefined. However when doing a nullable comparison, instead of returning **bool?** whose value is **null**, it simply returns **false** which is indistinguishable from a defined result of **false **when the comparison is not true.

In other words if **x** or **y** are nullable value types that support **<**, then:

**x < y**returns:**true**if**x**and**y**are both not**null**and**x.Value < y.Value****false**if**x**and**y**are both not**null**and**x.Value >= y.Value***also***false**if either**x**or**y**are**null**

It’s that second **false** that is problematic. Because with any of the relationship operators, we can assume that if **<** returns **false**, then **>=** should return **true! **But not so with **Nullable<T>** wrapped value types, so the assumption above, which works for non-nullable value types won’t work with **Nullable<T> **wrapped value types:

1: if (x < y)

` 2: {`

3: // x is less than y

` 4: }`

5: else if (x > y)

` 6: {`

7: // x is greater than y

` 8: }`

9: else

` 10: {`

11: // x and y must be equal by definition, right???

` 12: }`

So, again be aware that if you are using the **<, <=, >, **or **>= **relational comparison operators between **Nullable<T>** wrapped value types, you will always get a **false** if one of the values is **null** regardless of the value of the other. Protect yourself by checking the **HasValue** property first or comparing against **null** using **== **or** != **operators which do work as expected against **null**.

Or, you can choose to use the **Nullable.Compare<T>()** method, which considers **null** to be less than any other value, if that is where you consider **null** to be ranked in the ordering of your type.

### Summary

When using performing arithmetic or comparison operators directly against a **Nullable<T>** wrapped value type, make sure you know exactly what will happen if one of the operands is **null**!

Better yet, either compare the operands to **null** or query the **HasValue** property to make sure a value exists before you attempt to compare it or involve it in arithmetic.

Alternatively, you can use the **Compare<T>()** method in the **Nullable** static class to compare nullable types, with the understanding that **null** is considered less than any valid value (even the minimum negative values)**.**

Tweet |
Technorati Tags: C#,CSharp,.NET,Little Pitfalls,Nullable,Operator overloading |

- Share This Post:
- Short Url: http://wblo.gs/c2U

Print | posted on Thursday, July 14, 2011 7:54 PM | Filed Under [ My Blog C# Software .NET Little Pitfalls ]

## Feedback

## # re: C#/.NET Little Pitfalls: Nullable Math Doesn’t Always Add Up

This behaviour exactly mirrors one of NaNs in floating-point arithmetic, so anybody familiar with NaNs should probably expect this.## # re: C#/.NET Little Pitfalls: Nullable Math Doesn’t Always Add Up

@Arseny: True, though the main wrinkle here is many people would expect a Nullable<T> to throw if used when its value is null. It's not saying the behavior is wrong, just something that novice developers should watch out for.## # re: C#/.NET Little Pitfalls: Nullable Math Doesn’t Always Add Up

Another good post. Thanks James.## # re: C#/.NET Little Pitfalls: Nullable Math Doesn’t Always Add Up

Thanks @David!## # re: C#/.NET Little Pitfalls: Nullable Math Doesn’t Always Add Up

As someone that works with SQL that behavior is the expected behavior. Very interesting post, the nullable type seems useful for working with data extracted from a database.## # re: C#/.NET Little Pitfalls: Nullable Math Doesn’t Always Add Up

Oh absolutely, I should clarify yhat the purpose of these articles is never to say the .NET Framework is wrong or C# is wrong. Just that some developers (ESP ones newer to C#) may have asumptions about behaviors that are incorrect.