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 Foodovrebbe contenere solo Foos - questo è l'intero punto del sistema di tipi! nullnon è Foopiù ciò che "Hello, world!"è. Peggio ancora, nullnon è 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 Foos. Nota che eseguire il controllo delle stringhe nello snippet precedente non propaga il fatto che foo1 sia davvero un Foo- barprobabilmente avrà anche un proprio controllo, solo per sicurezza.
Confronta quello con l'uso di un tipo Maybe/ Optioncon la corrispondenza del modello:
case maybeFoo of
| Just foo => bar(foo)
| Nothing => baz()
All'interno della Just fooclausola, sia tu che il programma sapete con certezza che la nostra Maybe Foovariabile contiene davvero un Foovalore - che le informazioni vengono propagate lungo la catena di chiamate e barnon è 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 Foocontengono davvero Foos. Tutti vincono.