Esistono molte risposte eccellenti che coprono gli sfortunati sintomi di null
, quindi mi piacerebbe presentare un argomento alternativo: Null è un difetto nel sistema dei tipi.
Lo scopo di un sistema di tipi è di garantire che i diversi componenti di un programma "si adattino" correttamente; un programma ben tipizzato non può "uscire dai binari" in un comportamento indefinito.
Considera un ipotetico dialetto di Java, o qualunque sia il tuo linguaggio tipizzato staticamente preferito, in cui puoi assegnare la stringa "Hello, world!"
a qualsiasi variabile di qualsiasi tipo:
Foo foo1 = new Foo(); // Legal
Foo foo2 = "Hello, world!"; // Also legal
Foo foo3 = "Bonjour!"; // Not legal - only "Hello, world!" is allowed
E puoi controllare le variabili in questo modo:
if (foo1 != "Hello, world!") {
bar(foo1);
} else {
baz();
}
Non c'è nulla di impossibile in questo: qualcuno potrebbe progettare un linguaggio del genere se lo volesse. Il valore speciale non deve essere "Hello, world!"
- potrebbe essere stato il numero 42, la tupla (1, 4, 9)
o, diciamo, null
. Ma perché lo faresti? Una variabile di tipo Foo
dovrebbe contenere solo Foo
s - questo è l'intero punto del sistema di tipi! null
non è un Foo
non più di "Hello, world!"
. Peggio ancora, null
non è un valore di qualsiasi tipo e non c'è niente che tu possa fare con questo!
Il programmatore non può mai essere sicuro che una variabile detenga effettivamente una Foo
, e nemmeno il programma; per evitare comportamenti indefiniti, deve controllare le variabili per "Hello, world!"
prima di utilizzarle come Foo
s. Tieni presente che eseguire il controllo stringa nello snippet precedente non fa propagare il fatto che foo1 è in realtà un Foo
- bar
probabilmente avrà anche il proprio controllo, solo per sicurezza.
Confrontalo con il tipo Maybe
/ Option
con la corrispondenza del modello:
case maybeFoo of
| Just foo => bar(foo)
| Nothing => baz()
All'interno della clausola Just foo
, sia tu che il programma siete sicuri che la nostra variabile Maybe Foo
contenga veramente un valore Foo
- tale informazione è propagata lungo la catena di chiamate e bar
non ha bisogno fare qualsiasi controllo Poiché Maybe Foo
è un tipo distinto da Foo
, sei costretto a gestire la possibilità che possa contenere Nothing
, quindi non puoi mai farlo alla cieca di un NullPointerException
. Puoi ragionare sul tuo programma molto più facilmente e il compilatore può omettere i controlli nulli sapendo che tutte le variabili di tipo Foo
contengono effettivamente Foo
s. Tutti vincono.