Friday, August 22, 2008

Wait Wait What? Nullable Types in C# 2.0?

So I just learned that C# 2.0 has nullable types. You can do this:

int? i = null;

And it works fine. I know the idea is that you can represent a non-answer or unknown entity this way, especially when dealing with databases and DBNull. Still, it seems like a bad idea in a lot of ways. I've spoken out against nulls before when dealing with booleans. But what about integers?

I don't like it. I'm all about conceptual integrity; one thing is one thing. So what is an integer? A whole number. Is null a whole number? No it's not.

So what's the flipside? Sometimes nulls exist. You're going to do a left-join one day, and then your integer column "reset_count" is going to be null. Now you have to code to use the "hasValue" boolean attached to the nullable int (you get "hasValue" for free with every nullable-type declaration). Every time you want to use that value, you have to add code:

if (i.hasValue)

If you have to add that code, then you really have to refactor your code. Whatever you're representing should be able to handle this one-to-zero-or-more relationship without special code. Maybe use a collection and "foreach" through it. Maybe you do something cool that I've never heard of. But if you have to code for nulls, please seriously consider refactoring.

Appendix: I can think of one condition where you might need to add your own "valueSpecified" boolean: classes that represent XSDs with optional attributes. I don't have to like it though.

4 comments:

Anonymous said...

Variable declarations without initialization should be initialized as null for even simple datatypes.

Or, even better yet, the concepts of null and nothing should not be interchanged. Vb.net should introduce null and C# nothing.

int i; //this is null
int i = 0;// this is nothing

However:
int i;
i = i +5; //what would this mean
(i = i+5) = null

I can live with this.

But a nullable type is a rather odd concept. To me, nullable types would be objects since the existence of the object itself cannot be nullified only its referential value. Or, in another way, would it really be possible to nullify an integer whose value is already known unless modifying it with a null? This would seem like a bad idea. So even the term 'nullable' leads down a dirty road.

So in short. Variable declaration without explicit initialization would be null value.

Unknown said...

You are forgetting the difference between value and reference types. Value types (e.g. integer) always have a value (integers default to 0). Reference types default to "null" in C# or "nothing" in VB.

Furthermore, your statement "int i = 0; //this is nothing" is totally ridiculous. Zero is a totally legit value for an integer; it shouldn't evaluate to nothing.

I see what you're saying about the difference between Null and Nothing, but the difference is so subtle that they should remain equivalent. If null means "not set or initialized" and nothing means "not pointed at anything", semantically in .NET those two ideas are as equivalent as you can get.

For example, let's talk about a stringbuilder:

StringBuilder sb;

At this point, sb == null (VB: sb = Nothing). Next step:

sb = new StringBulder();

Now, sb != null (VB: sb <> Nothing). Where's the inbetween?

jozef said...

That is my point. A nullable integer doesn't make sense. By it being an integer its value is already in a knowable range. A nullable integer should be an 'object' since its reference is to something unknown and itself does not have a known value.

When a null is retrieved from the database, it is in essence, an untyped object/value. We retrieve its type by referring to the schema definition of the table and making inferences that its supposed type is of the same type as the schema.

When I said i=0 would be nothing, I should have been clearer. It means less than 1 or empty or default. From a purely theoretical point of view, the idea of setting a value to 'null' is ridiculous. It is as if somewhere along the lines of thought, you lost the integer and when you found it again it is unknowable.

Perhaps my point would had better been put like this.

The separation between value types and reference types would seem to be obliterated if we have nullable value types. At that point, we would just conceivably be using objects with restricted uses. (An integer is always a x,y,z).

What would it even mean to say

int i;
i= null;

So then a nullable type is just an undefined object? A space holder? Maybe that's the magic, but I just don't get it. I would prefer to have things which are unknowable tested for nullability and recast or the value reset rather than have every type subjected to possible nullability.

Unknown said...

I think we are in agreement for the most part. We both don't like the idea of nullable types.

If you really need something like a nullable type, you should wrap that int in a class:

public class ZipCode
{
public int? ZipCode;
}


That's a silly example, but I'd rather do something like that if I really had to represent nulls.

I guess my main point was that you shouldn't use nullable types, and if you need to, you should refactor your code as to not need them. And it sounds like we agree on this.

All rights reserved. Take that!