views:

1486

answers:

6

I've been searching for some good guidance on this since the concept was introduced in .net 2.0.

Why would I ever want to use non-nullable data types in c#? (A better question is why wouldn't I choose nullable types by default, and only use non-nullable types when that explicitly makes sense.)

Is there a 'significant' performance hit to choosing a nullable data type over its non-nullable peer?

I much prefer to check my values against null instead of Guid.empty, string.empty, DateTime.MinValue,<= 0, etc, and to work with nullable types in general. And the only reason I don't choose nullable types more often is the itchy feeling in the back of my head that makes me feel like it's more than backwards compatibility that forces that extra '?' character to explicitly allow a null value.

Is there anybody out there that always (most always) chooses nullable types rather than non-nullable types?

Thanks for your time,

+6  A: 

Because it's inconvenient to always have to check whether the nullable type is null.

Obviously there are situations where a value is genuinely optional, and in those cases it makes sense to use a nullable type rather than magic numbers etc, but where possible I would try to avoid them.

// nice and simple, this will always work
int a = myInt;

// compiler won't let you do this
int b = myNullableInt;

// compiler allows these, but causes runtime error if myNullableInt is null
int c = (int)myNullableInt;
int d = myNullableInt.Value;    

// instead you need to do something like these, cumbersome and less readable
int e = myNullableInt ?? defaultValue;
int f = myNullableInt.HasValue ? myNullableInt : GetValueFromSomewhere();
LukeH
I guess this is my point though. Potentially myNonNullableInt will have not been set yet, and will have the default 0 value in it which is just as invalid for my business domain than null. So I have to make a check anyway. And I prefer myNullableInt != null to myNonNullableInt > 0
Matthew Vines
Even for non-local scope it makes sense to only use nullable types where appropriate: if a value can never actually be null then why declare it as nullable, meaning every piece of code that deals with that type has to do extra checks etc.
LukeH
A: 

I tend to use Nullable types wherever they make sense -- I won't care about performance until it's a problem, then I'll fix the few areas where it is and be done with it.

However, I also find that in general, most of my values end up being non-nullable. In fact, there are many times I'd actually like a NotNullable I can use with reference types to find out about a null problem when I get the null, not later on when I try to use it.

Jonathan
+2  A: 

I think the language designers feel that 'reference types being nullable by default' was a mistake, and that non-nullable is the only sensible default, and you should have to opt into nullness. (This is how it is in many modern functional languages.) "null" is usually a heap of trouble.

Brian
You say the language designers want to "move away" from nullness, but they actually ADDED nullability to value types, which couldn't be null before. And reference types are still null by default, with no way to opt out. I don't understand your reasoning.
Lucas
Here's a better way to characterize the position of some language designers. We have two kinds of types: value types and reference types. We have two kinds of types: nullable types and non-nullable types. We started with a type system where all reference types were nullable and all value types were non-nullable. We then added nullable value types. But adding non-nullable reference types is extremely hard now. It would have been better to design the type system to allow for all four possibilities in the first place.
Eric Lippert
Yes, what Eric said is great. I'll add that nullability for value types is a specific win for some interop scenarios (with e.g. SQL databases). But non-nullability for most types is a general win for most code from a general software engineering perspective.
Brian
+3  A: 

You seem to have 2 different questions...

Why would I ever want to use non-nullable data types in C#?

Simple, because the value-type data you're relying on is guaranteed by the compiler to actually have a value!

Why wouldn't I choose nullable types by default, and only use non-nullable types when that explicitly makes sense?

As Joel has already mentioned, a type can only be null if it is a reference type. Value types are guaranteed by the compiler to have a value. If your program depends on a variable to have a value, then this is the behavior you will want by not choosing a nullable type.

Of course, when your data is coming from anywhere that is not your program, then all bets are off. The best example is from a database. Database fields can be null, so you would want your program variable to mimic this value - not just create a "magic" value (i.e. -1, 0, or whatever) that "represents" null. You do this with nullable types.

John Rasch
As mentioned in the other answers/comments, nullable types *are* value types but they're not guaranteed to have a value. (That's what the HasValue property is there for!)
LukeH
It's ok, he meant "non-nullable value types" :)
Lucas
A: 

Although null values can be convenient for using as "not-initialized-yet" or "not-specified" values, they make the code more complex, mainly because you're overloading the meaning of null as well as the variable (number-or-null vs. just-a-number).

NULL values are favoured by many database designers and SQL database programmers but with a small change in thinking about the problem you can do away with null values and actually have simpler and more reliable code (e.g., no worrying about NullReferenceExceptions).

There's actually a large demand for a "T!" operator that makes any reference type non-nullable, similar to how "T?" makes value types nullable, and Anders Hejlsberg, the inventor of C#, wished he had included the ability.

See also the question, Why is “null” present in C# and java?

Mark Cidade
+19  A: 

The reason why you shouldn't always use nullable types is that sometimes you're able to guarantee that a value will be initialized. And you should try to design your code so that this is the case as often as possible. If there is no way a value can possibly be uninitialized, then there is no reason why null should be a legal value for it. As a very simple example, consider this:

List<int> list = new List<int>()
int c = list.Count;

This is always valid. There is no possible way in which c could be uninitialized. If it was turned into an int?, you would effectively be telling readers of the code "this value might be null. Make sure to check before you use it". But we know that this can never happen, so why not expose this guarantee in the code?

You are absolutely right in cases where a value is optional. If we have a function that may or may not return a string, then return null. Don't return string.Empty(). Don't return "magic values".

But not all values are optional. And making everything optional makes the rest of your code far more complicated (it adds another code path that has to be handled).

If you can specifically guarantee that this value will always be valid, then why throw away this information? That's what you do by making it a nullable type. Now the value may or may not exist, and anyone using the value will have to handle both cases. But you know that only one of these cases is possible in the first place. So do users of your code a favor, and reflect this fact in your code. Any users of your code can then rely on the value being valid, and they only have to handle a single case rather than two.

jalf
This is a really good answer to the question, but it makes me want to revise it. Why shouldn't I always use Nullable types for Bussiness Domain Class Properties in Enterprise Applications? Which I think I probably can most of the time. Thanks for your time.
Matthew Vines
I think the same rules of thumb apply there. Can you guarantee that the property will always be valid? (Your object will probably always have an ID, so no point in making that nullable. But other properties may or may not exist, depending on the state of the object. But remember that *if* you can make a value non-nullable, that makes it a lot nicer to work with in the future, because users don't have to check it against null. So see if it is possible to guarantee that the property is valid, and if so, don't make it nullable.
jalf