We noticed that lots of bugs in our software developed in C# (or Java) cause a NullReferenceException.
Is there a reason why \"null\" has even been included in the l
I can't speak to your specific issue, but it sounds like the problem isn't the existence of null. Null exists in databases, you need some way to account for that in the application level. I don't think that's the only reason it exists in .net, mind you. But I figure it's one of the reasons.
Sorry for answering four years late, I am amazed that none of the answers so far have answered the original question this way:
Languages like C# and Java, like C and other languages before them, have null
so that the programmer can write fast, optimized code by using pointers in an efficient way.
A little history first. The reason why null
was invented is for efficiency. When doing low-level programming in assembly, there is no abstraction, you have values in registers and you want to make the most of them. Defining zero to be a not a valid pointer value is an excellent strategy to represent either an object or nothing.
Why waste most of the possible values of a perfectly good word of memory, when you can have a zero-memory-overhead, really fast implementation of the optional value pattern? This is why null
is so useful.
Semantically, null
is in no way necessary to programming languages. For example, in classic functional languages like Haskell or in the ML family, there is no null, but rather types named Maybe or Option. They represent the more high-level concept of optional value without being concerned in any way by what the generated assembly code will look like (that will be the compiler's job).
And this is very useful too, because it enables the compiler to catch more bugs, and that means less NullReferenceExceptions.
In contrast to these very high-level programming languages, C# and Java allow a possible value of null for every reference type (which is another name for type that will end up being implemented using pointers).
This may seem like a bad thing, but what's good about it is that the programmer can use the knowledge of how it works under the hood, to create more efficient code (even though the language has garbage collection).
This is the reason why null
still exists in languages nowadays: a trade-off between the need of a general concept of optional value and the ever-present need for efficiency.
After all, if there were no "null", I would have no bug, right?
The answer is NO. The problem is not that C# allows null, the problem is that you have bugs which happen to manifest themselves with the NullReferenceException. As has been stated already, nulls have a purpose in the language to indicate either an "empty" reference type, or a non-value (empty/nothing/unknown).
The feature that couldn't work without null is being able to represent "the absence of an object".
The absence of an object is an important concept. In object-oriented programming, we need it in order to represent an association between objects that is optional: object A can be attached to an object B, or A might not have an object B. Without null we could still emulate this: for instance we could use a list of objects to associate B with A. That list could contain one element (one B), or be empty. This is somewhat inconvenient and doesn't really solve anything. Code which assumes that there is a B, such as aobj.blist.first().method()
is going to blow up in a similar way to a null reference exception: (if blist
is empty, what is the behavior of blist.first()
?)
Speaking of lists, null lets you terminate a linked list. A ListNode
can contain a reference to another ListNode
which can be null. The same can be said about other dynamic set structures such as trees. Null lets you have an ordinary binary tree whose leaf nodes are marked by having child references that are null.
Lists and trees can be built without null, but they have to be circular, or else infinite/lazy. That would probably be regarded as an unacceptable constraint by most programmers, who would prefer to have choices in designing data structures.
The pains associated with null references, like null references arising accidentally due to bugs and causing exceptions, are partially a consequence of the static type system, which introduces a null value into every type: there is a null String, null Integer, null Widget, ...
In a dynamically typed language, there can be a single null object, which has its own type. The upshot of this is that you have all the representational advantages of null, plus greater safety. For instance if you write a method which accepts a String parameter, then you're guaranteed that the parameter will be a string object, and not null. There is no null reference in the String class: something that is known to be a String cannot be the object null. References do not have type in a dynamic language. A storage location such as a class member or function parameter contains a value which can be a reference to an object. That object has type, not the reference.
So these languages provide a clean, more or less matematically pure model of "null", and then the static ones turn it into somewhat of a Frankenstein's monster.
Null is an extremely powerful feature. What do you do if you have an absence of a value? It's NULL!
One school of thought is to never return null, another is to always. For example, some say you should return a valid but empty object.
I prefer null as to me it's a truer indication of what it actually is. If I can't retrieve an entity from my persistence layer, I want null. I don't want some empty value. But that's me.
It is especially handy with primitives. For example, if I have true or false, but it's used on a security form, where a permission can be Allow, Deny, or not set. Well, I want that not set to be null. So I can use bool?
There are a lot more I could go on about, but I will leave it there.
I'm surprised no one has talked about databases for their answer. Databases have nullable fields, and any language which will be receiving data from a DB needs to handle that. That means having a null value.
In fact, this is so important that for basic types like int you can make them nullable!
Also consider return values from functions, what if you wanted to have a function divide a couple numbers and the denominator could be 0? The only "correct" answer in such a case would be null. (I know, in such a simple example an exception would likely be a better option... but there can be situations where all values are correct but valid data can produce an invalid or uncalculable answer. Not sure an exception should be used in such cases...)