In programming, the concepts of null, nothing, undefined, and none are fundamental for handling the absence of values.
It seems like a simple thing that most programmers use every day. But, in reality, the concept of “absence of value” is surprisingly complex and has been a source of countless debates and headaches.
Recall that we said a variable is a box. In the physical world, if you have a box, it can have something inside or be empty. It’s a simple concept.
But in programming, an empty box is usually not an empty box. It’s a box that contains ‘nothing’. That is, it contains this:

The “Billion-Dollar Mistake”
Before diving into how it works in each language, let’s emphasize. null has a very bad reputation (and for good reason).
The concept of a null reference was introduced in 1965 by Tony Hoare (creator of the QuickSort algorithm) while designing the ALGOL W language. Decades later, at a conference, he publicly apologized, saying:
“I call it my billion-dollar mistake. […] I simply couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes.” — Tony Hoare
The fundamental problem is that null breaks the type system. If you have a variable of type Student, you expect it to have a student. Not a ticking time bomb waiting to explode.
But if it’s null, and you try to ask for its length (student.length), your program crashes. It’s the infamous NullReferenceException or Segmentation Fault.
To avoid this error, which is the most common error in programming, programmers are forced to “armor” their code with checks like:
if(student == null) return;
“Nothing” in Different Languages
Depending on the language you use, you’ll encounter null, undefined, None, nil, or nullptr. They all try to say the same thing: “this variable contains nothing”.
Let’s see how each ecosystem tackles this problem, because there are important nuances.
In low-level languages, variables are memory addresses. Here, the absence of value is literally the number 0.
- NULL: In classic C,
NULLis simply a macro that equals0. That is, memory address 0. - nullptr: In modern C++ (C++11 onwards),
nullptrwas introduced. This solves ambiguity problems. WhileNULLcould be confused with the integer 0,nullptris its own safe type.
// C++
int* pointer = nullptr; // The pointer doesn't point to any valid address
If you try to read what’s at the memory address of a nullptr, the Operating System stops your program immediately to prevent memory corruption.
In these object-oriented languages, we distinguish between
- Value types (like an
int) - Reference types (like a
class).
Traditionally, an int can never be null (it’s always 0 or a number). But any object (a string, a User) is a reference that can point to an object in the Heap or to null.
// C#
string name = null; // Valid
int age = null; // Compilation Error! (in older versions)
Here null means “this reference variable is not associated with any object instance”.
Python has a very elegant approach. Here, null doesn’t exist; there is None.
The big difference is that None is an object itself. It’s the sole instance of the NoneType class.
# Python
value = None
if value is None:
print("There's nothing")
Being a real object, None behaves more predictably than C++‘s null pointer.
JavaScript, in its infinite peculiarity, decided that having just one way to represent nothing was too little, so it has two:
- undefined: Means “this variable has been declared, but no value has been assigned to it yet”. It’s the default value of things.
- null: Means “this variable intentionally has an absence of value”.
let a;
console.log(a); // undefined (the system tells me it's empty)
let b = null;
console.log(b); // null (I, the programmer, say it should be empty)
Trying to Fix the Mistake: Optionals and Nullables
Since null causes so many unexpected application crashes, modern languages have developed mechanisms to force us to handle the absence of value.
Languages like C# or Kotlin introduce the concept of nullable types. For example, modern C# introduced a strict distinction.
Now, if you want something to be nullable, you have to explicitly mark it with a question mark ?.
string text = null; // Warning or Error: This shouldn't be null!
string? text2 = null; // Correct: I explicitly said it can be.
The Optional type (Java, C++, Rust) is a more functional solution. Instead of returning an object or null, you wrap the object in a “box” called Optional.
The box can be full or empty. To use the value, you are forced to first check if the box has something.
// C++ std::optional
std::optional<int> findValue() { ... }
auto result = findValue();
if (result.has_value()) {
// Use the value
}
This eliminates the surprise. You no longer assume the value exists; the data type forces you to handle the empty case.
To make life easier, many languages have added “Safe Navigation” Operators to work with nulls without filling the code with if (x != null).
- Null Coalescing (
??): “If it’s null, use this default value”.
let name = userInput ?? "Anonymous";
- Optional Chaining (
?.): “If it’s null, don’t proceed and return null, but don’t explode”.
// If user is null, don't try to access address.
// If address is null, don't try to access street.
var street = user?.address?.street;
