Ci sono molte risposte eccellenti che coprono gli sfortunati sintomi di null
, quindi vorrei presentare un argomento alternativo: Null è un difetto nel sistema dei tipi.
Lo scopo di un sistema di tipi è quello di garantire che i diversi componenti di un programma "si incastrino" correttamente; un programma ben tipizzato non può "spaccare le rotaie" in un comportamento indefinito.
Prendi in considerazione un ipotetico dialetto di Java, o qualunque sia la tua lingua preferita digitata staticamente, 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é dovresti farlo? Una variabile di tipo Foo
dovrebbe contenere solo Foo
s - questo è l'intero punto del sistema di tipi! null
non è Foo
più ciò che "Hello, world!"
è. Peggio ancora, null
non è un valore di alcun tipo e non c'è niente che tu possa farci!
Il programmatore non può mai essere sicuro che una variabile contenga effettivamente un Foo
, e nemmeno il programma; per evitare comportamenti indefiniti, deve controllare le variabili "Hello, world!"
prima di usarle come Foo
s. Nota che eseguire il controllo delle stringhe nello snippet precedente non propaga il fatto che foo1 sia davvero un Foo
- bar
probabilmente avrà anche un proprio controllo, solo per sicurezza.
Confronta quello con l'uso di un tipo Maybe
/ Option
con la corrispondenza del modello:
case maybeFoo of
| Just foo => bar(foo)
| Nothing => baz()
All'interno della Just foo
clausola, sia tu che il programma sapete con certezza che la nostra Maybe Foo
variabile contiene davvero un Foo
valore - che le informazioni vengono propagate lungo la catena di chiamate e bar
non è necessario effettuare alcun controllo. Perché Maybe Foo
è un tipo distinto da Foo
, sei costretto a gestire la possibilità che possa contenere Nothing
, quindi non puoi mai essere accecato da un NullPointerException
. Puoi ragionare sul tuo programma molto più facilmente e il compilatore può omettere controlli null sapendo che tutte le variabili di tipo Foo
contengono davvero Foo
s. Tutti vincono.