2

The question is in the title. Here is the context:

Some people think that the null pointer is a big mistake. Tony Hoare famously apologized for inventing it. Since version 2.0 C# has had nullable value types (int? foo;), which introduces more of the null badness into the language. To confuse the issue, the C# team is considering adding non-nullable reference types too (MyClass! myClass).

So are we trying to increase or decrease null pointers? Why are null pointers bad? If they are bad, why did the C# team expand the language's ability to use them? If they are good, why might the C# team expand the language's ability to prevent them? When we are reviewing code, how do we decide whether a variable or property should be allowed to be null or not?

In short: when do the benefits of a nullable value type outweigh the cost of a null pointer?

6 Answers6

6

So C#'s nullable types aren't adding null pointers. They're an Option type, where you are explicitly saying "this can be unspecified/null/empty", and users have to explicitly call .Value (or a cast) to get the value. In C++, and C# reference types (and many other places), things can be null, but normally aren't. Programmers get lazy, and boom, badtimes.

And these sorts of things are necessary because sometimes stuff is optional. You have to represent that somehow.

But C# reference types always allow null, even when things aren't optional. So it falls to the programmer to check every variable. By letting the type system do this for you, it reduces the chance for error, while still letting you specify optional types when you need them.

Telastyn
  • 110,259
2

A null value is something different than a null pointer, there is no relation nor meaningful comparison other than they both express "not there". Traditional value types have no way for expressing the value is not there, every possible state of an instance is a value. For instance, there is no way to tell if an integer variable with a value of 0 still has the default initial value because no result has been asigned to it yet or the result was just 0. Solutions like "OK, if it is 999 that means unknown" are hardly satisfying. So nullable value types do have value, particularly because they do not necessarily have a value.

Also look up in-band signaling for an analogy.

Martin Maat
  • 18,652
2

Hoare did not apologize for inventing the null-pointer. The null-pointer is useful and often necessary. You can't implement say a linked list without null pointers.

What Hoare considered a mistake was to design a type system where every object reference always was nullable. Not all reference types need to be nullable, indeed it is probably the minority. If a variable is never supposed to be null, indicating it in the type system would allow the compiler to statically detect and flag cases where it was assigned a null value or never initialized properly.

Nullable value types does not really have anything to do with null pointers, but they are similar to object references in that they have a "special" value called null. Since you can explicit specify if the type should be nullable or not, this is exactly like Hoare would have wanted.

A variable should be allowed to be nullable if it sometimes have no semantically valid value.

JacquesB
  • 61,955
  • 21
  • 135
  • 189
1

You asked several other questions in the post, so I will take your first line literally and focus on just the title.

I believe the immediate answer to your question is in the negative. i.e., that are no benefits of actually following a pointer to null values UNLESS you are in a multitasking/multiuser environment.

Having a null pointer means there is no chance that there will ever be a value to be obtained by using that particular pointer variable, so you save a bit of processor time in doing a lookup only to find a null value. The pointer is invalid in the first place.

But in a multiuser environment, it might be important to monitor a variable or database element to look for the presence of other data, as indicated by the presence of non-null values. In this case, the lookup is justified because it can cause your program to make a decision such as looking at the rest of a data record once something is not null, or to stop looking for further data if the value of an element becomes null - like if the data row has been deleted.

So the direct answer to your question is that the benefit of having nullable data types is that it can help with synchronization of multiple users looking into the same table.

SDsolar
  • 139
1

A pointer can always be a null pointer. You never know. But instead of pointers which can be null you can use two different types: "References" which must always have an object that they refer to, and "optional references" which are either references or nil. Now a plain reference (we could call it a non-optional reference) will never be nil, 100% guaranteed. Swift doesn't even allow you to check if it is nil! An optional reference can be nil, but then you cannot use it without checking.

Converting code from pointers to references and optional references, I noticed that I started out with quite a bit of code that handled null pointers (because I couldn't know whether any particular pointer could become null or not), and then I figured out that I could replace the pointer with a (non-optional) reference - so lots of checking code just disappeared, making my code faster and simpler. (Other pointers changed to optional references because they could become nil).

Another huge advantage of optionals is that any type has a corresponding optional type. So for example a function that converts a string into a number now has a very simple way to indicate success or failure: The type it returns is an optional integer or optional double, and it returns nil on failure.

You seem to completely misunderstand C#'s nullable types (or Swift optionals): Null pointers are not the problem. The fact that any pointer can be a null pointer is the problem. Nullable types / optional types clean up that mess by having a clear distinction between pointers that can never be null, and pointers that can. And it is impossible to just reference the thing that a nullable pointer would point to if it is not nil, without checking first.

gnasher729
  • 49,096
1

Null values exist, sometimes the value just doesn't apply and sometimes it does but you don't have it. That has to be modeled somehow.

For value types, they modeled that with a Nullable struct, which conceptionally is NOT a null reference, it always has a value and all of the methods on it always work (Value sometimes throws an exception, but that is correct behavior under the circumstances).

Reference types historically model this fact with null reference/pointers. That is not actually a problem. As has been recognized recently, the REAL problem is not having a way of requiring that a reference type MUST HAVE a value.

Without that, method calls that take or return reference type, break the programmers ability to reason about what the program will do. The method can expect that the value is not null, but there is no way to enforce it. Which means the programmer either adds checks manually, checks which are mainly useless and get duplicated time after time, or lets the program crash when someone inevitably makes a mistake and doesn't provide a value. Worse, when adding the checks to try to prevent a crash, the programmer has to figure out what to do when a value that MUST be there, isn't.

Non-nullable references fix this -- the compiler knows when a value might be null, and prevents a reference from being passed to or returned from a method where it could be null but MUST not be. Now you can have the equivalent of method(primitive value) where if you try to call it with method(new Nullable()) it won't crash, because it just won't compile.

TL;DR version: nullable types are not the same as reference types, because it ONLY makes sense to accept or return them when the value could be null. And you can have methods that return the non-nullable value type. With "regular" reference types you have to accept and return them regardless of whether the value can be null or not.

jmoreno
  • 11,238