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?

3

6 Answers 6

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.

6
  • There seems to be some controversy about whether Nullable is an option type or not: stackoverflow.com/a/11147088/1108891 Commented Jan 21, 2017 at 3:50
  • 1
    @ShaunLuttin - Yes, it isn't quite a typical functional option type, but it's more like those than a C style pointer.
    – Telastyn
    Commented Jan 21, 2017 at 4:00
  • Reference source: referencesource.microsoft.com/#mscorlib/system/nullable.cs Commented Jan 21, 2017 at 4:02
  • So, am I understanding correctly? Marking a value-type property as nullable is tantamount to saying, "Let the user (or client application) abstain from providing a value, in which case we want to know that the user abstained (or forgot...) instead of assuming that the user provided the default value." Commented Jan 21, 2017 at 4:22
  • 1
    @ShaunLuttin: Not quite. I read Nullable<T> as saying "give value types similar null semantics as reference types already have." Commented Jan 21, 2017 at 20:43
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.

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.

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.

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.

7
  • I'm struggling to understand your answer. You wrote, "If you use optional references to objects, then a non-optional reference will never be nil..." How can we have a non-optional reference, if we are using optional references? Commented Jan 21, 2017 at 22:17
  • Is your answer using null and nil as synonyms? Commented Jan 21, 2017 at 22:19
  • "Converting code from pointers to references and optionals..." I'm struggling to understand the terms here. By "references" do you mean mandatory references? By "optionals" do you mean optional references? Commented Jan 21, 2017 at 22:23
  • 1
    @ShaunLuttin: In Swift, for example, a reference can never be nil. It always refers to an existing object. An optional reference is not a reference with an "optional" attribute, but a thing that is either a reference or nil. Just like an optional Integer is either an integer or nil, and an optional string is either a string or nil.
    – gnasher729
    Commented Jan 22, 2017 at 0:01
  • 1
    @ShaunLuttin: With a non-optional or mandatory reference, you always have a reference, which your program sees, and an actual nameless object, that the reference refers to. You "dereference" the reference, and in doing so you "reference" the object that the reference referred to.
    – gnasher729
    Commented Jan 22, 2017 at 0:13
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.

2
  • Is the C#'s language team's proposal for nullable reference types an attempt to solve the REAL problem? github.com/dotnet/roslyn/issues/5032 Commented Jan 22, 2017 at 16:32
  • 1
    @ShaunLuttin: the discussion for that has gotten MUCH bigger since I read all of it, but the basic idea is an attempt to address the real problem. There may be a weak spot in the implementation with reflection, and there almost certainly is with interacting with code produced by older compilers. So, it's probably not going to be the "solution", but rather an improvement that improves the situation as time goes by.
    – jmoreno
    Commented Jan 22, 2017 at 17:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.