This is exactly the same way: null in C # is a uniquely erroneous solution, thoughtlessly copied from earlier languages.
The worst thing is that the universal traitor can be used as the value of any reference type - null, to which the compiler does not react. But at the time of execution it is easy to get a knife in the back - NullReferenceException . It is useless to handle this exception: it means an unconditional error in the code.
Pepper to wound: failure (NRE when trying to dereference) can be very far from the defect (use null where a full-fledged object is waiting).
Plump fur animal: null is incurable - no future innovations in the platform and language will save us from the leper inherited code, which is physically impossible to stop using.
Of course, it was, moreover, it was obvious by modern standards.
Unified Nullable for significant and reference types.
Nullable dereferencing only through special operators ( ternary -?: , Elvis -?. , Coalesce - ?? ), providing for the mandatory processing of both variants (presence or absence of an object) without throwing out exceptions.
Examples:
object o = new object(); // -
object o = null; // - , null
object? n = new object; // nullable -
object? n = null; // nullable -
object o = n; // - , object object?
object o = n ?? new object(); // fallback (coalesce), n != null
Type t = n ? value.GetType() : typeof(object); // - value n, null
Type? t = n ? value.GetType(); // ? - null, null, , nullable