Null values or nullable types have posed long standing problems for computer scientists and language implementors alike. Technically speaking, nulls represent missing or unknown information, which is a perfectly valid condition that actually occurs in real programming situations. On the other hand, they also present questions such as "are two nulls ever equal?" and "what is the semantic value of a null?", which are concerns that can easily make or break a system. In some languages, C being a notable example, nulls do not have any formal handling and can easily lead to errors.
The general consensus in computer science is that nulls are never equal to other nulls. The idea is that since a null represents an unknown value, and two unknown values cannot be proven to be equal, two nulls thus cannot be proven equal either. However, I should note that as unknowns they also cannot be proven to be unequal, either, so this solution is not fully valid but rather just an attempt to present a consistent practical solution. This is also the solution taken by SQL, and it's an important question since unknowns occur very frequently in database code, and represent important edge cases.
There is also another problem with nulls, since in some cases they can represent the absence of a property, which gives them similar meaning to boolean 'false' in conditional statements. In some languages, notably lua, nulls are semantically equivalent to false for this reason, but this introduces another problem. Consider a situation where you have a boolean that might also be null. In that case it may be necessary to be able to distinguish between null and false. Nullable types are a solution to this problem, but they don't formally address the previous problem, nor do they give a formal semantic meaning to nulls in general.
I propose a solution which completes nullable types as a formal answer to the null problem, based around the key observation that nulls are not merely unknown, but rather from the perspective of the program they don't exist at all. As a consequence nulls cannot be compared because their values do not exist. Nulls also cannot be (directly) equivalent to false, again because their values do not exist. Instead, nullable types have an additional property, which is that they do or do not exist.
By performing an explicit 'exists check' on nullable types, the 'null or not null' property can be properly converted into a boolean which can then be used to determine how to handle the value, ie whether it can be compared and used or not, without having to resort to voodoo semantics by casting them to booleans or unconditionally returning 'false' when comparing them. By requiring null guards for nullable types, and by providing such checks in the compiler, it should be possible to statically guarantee correct behavior which fully satisfies all the practical and theoretical properties of nulls.
As a side note, the most common usage of nullable types (which typically only appear in pure functional languages) is for error handling, ie if a function can fail it might do so by making its outputs null. I personally disagree with this usage, from both the perspective of nulls and from the perspective of error handling, which I'll talk about more in my next article.