Ich verstehe das konsequente Bashing von Null-Referenzen durch einige Programmiersprachen nicht ganz. Was ist so schlimm an ihnen? Wenn ich Lesezugriff auf eine Datei anfordere, die nicht vorhanden ist, freue ich mich sehr über eine Ausnahme oder einen Nullverweis, und dennoch werden Ausnahmen als gut, aber Nullverweise als schlecht angesehen. Was ist der Grund dafür?
programming-languages
exceptions
null
davidk01
quelle
quelle
Antworten:
NULL-Referenzen werden nicht "gemieden" als Ausnahmen, zumindest von niemandem, den ich jemals gekannt oder gelesen habe. Ich denke, Sie verstehen die konventionelle Weisheit falsch.
Schlecht ist der Versuch, auf eine Nullreferenz zuzugreifen (oder einen Nullzeiger zu dereferenzieren usw.). Das ist schlecht, weil es immer einen Fehler anzeigt; Sie würde nie so etwas wie dies absichtlich tun, und wenn Sie sind es absichtlich tut, dann ist das noch schlimmer, weil es unmöglich zu unterscheiden , das erwartete Verhalten von Buggy Verhalten bewegt.
Es gibt bestimmte Randgruppen da draußen, die das Konzept der Nichtigkeit aus irgendeinem Grund wirklich hassen, aber wie Ed betont , wenn Sie es nicht haben
null
odernil
dann müssen Sie es einfach durch etwas anderes ersetzen, was zu etwas führen könnte schlimmer als ein Absturz (z. B. Beschädigung von Daten).Tatsächlich umfassen viele Frameworks beide Konzepte. In .NET ist ein häufiges Muster beispielsweise ein Methodenpaar, dem das Wort
Try
(z. B.TryGetValue
) vorangestellt ist . In diesemTry
Fall wird die Referenz (normalerweisenull
) auf den Standardwert gesetzt , und in dem anderen Fall wird eine Ausnahme ausgelöst. Bei beiden Ansätzen ist nichts falsch. beide werden häufig in Umgebungen verwendet, die sie unterstützen.Es hängt wirklich alles von der Semantik ab. Wenn
null
es sich um einen gültigen Rückgabewert handelt, wie im allgemeinen Fall der Suche in einer Sammlung, dann geben Sie zurücknull
. Wenn es sich jedoch nicht um einen gültigen Rückgabewert handelt, z. B. um das Nachschlagen eines Datensatzes mit einem Primärschlüssel aus Ihrer eigenen Datenbank, ist das Zurückgebennull
eine schlechte Idee, da der Aufrufer dies wahrscheinlich nicht erwartet Ich werde nicht danach suchen.Es ist wirklich sehr einfach herauszufinden, welche Semantik verwendet werden soll: Ist es sinnvoll, wenn das Ergebnis einer Funktion undefiniert ist? In diesem Fall können Sie eine Nullreferenz zurückgeben. Wenn nicht, eine Ausnahme auslösen.
quelle
null
, also wirklich, Haskell hier ziemlich irrelevant ist.null
es so lange so gut ausgehalten hat, und die Mehrheit der Leute, die etwas anderes sagen, scheinen Akademiker mit wenig Erfahrung darin zu sein, echte Apps mit Einschränkungen wie unvollständigen Anforderungen oder etwaiger Konsistenz zu entwerfen.Der große Unterschied besteht darin, dass, wenn Sie den Code für die Behandlung von NULL-Werten weglassen, der Code möglicherweise zu einem späteren Zeitpunkt mit einer nicht zusammenhängenden Fehlermeldung weiter abstürzt, wobei die Ausnahme wie bei Ausnahmen beim ersten Fehler (Öffnen) ausgelöst wird eine Datei zum Lesen in Ihrem Beispiel).
quelle
Da Nullwerte kein notwendiger Bestandteil einer Programmiersprache sind und eine konsistente Fehlerquelle darstellen. Wie Sie sagen, kann das Öffnen einer Datei zu einem Fehler führen, der entweder als Nullrückgabewert oder über eine Ausnahme zurückgemeldet werden kann. Wenn Nullwerte nicht zulässig sind, gibt es eine einheitliche Möglichkeit, Fehler zu kommunizieren.
Dies ist auch nicht das häufigste Problem bei Nullen. Die meisten Leute denken daran, nach dem Aufruf einer Funktion, die sie möglicherweise zurückgibt, auf null zu prüfen. Das Problem taucht viel häufiger in Ihrem eigenen Design auf, indem Sie zulassen, dass Variablen an verschiedenen Stellen der Programmausführung null sind. Sie können Ihren Code so gestalten, dass NULL-Werte niemals zulässig sind. Wenn NULL jedoch auf Sprachebene nicht zulässig wäre, wäre dies nicht erforderlich.
In der Praxis benötigen Sie jedoch noch eine Möglichkeit, um anzugeben, ob eine Variable initialisiert ist oder nicht. Sie haben dann eine Art Fehler, bei dem Ihr Programm nicht abstürzt, sondern weiterhin einen möglicherweise ungültigen Standardwert verwendet. Ich weiß ehrlich gesagt nicht, was besser ist. Für mein Geld stürze ich gerne früh und oft.
quelle
null
als Rückgabewert erhalten: Die angeforderten Informationen sind nicht vorhanden. Es gibt keinen Unterschied. In beiden Fällen muss der Aufrufer den Rückgabewert validieren, wenn er diese Informationen tatsächlich für einen bestimmten Zweck verwenden muss. Ob es sich um die Validierung einesnull
Objekts, eines Nullobjekts oder einer Monade handelt, spielt praktisch keine Rolle.Tony Hoare, der in erster Linie die Idee einer Nullreferenz erfunden hat, nennt sie einen Fehler von einer Million Dollar .
Das Problem betrifft nicht Null-Referenzen per se, sondern das Fehlen einer ordnungsgemäßen Typprüfung in den meisten (sonst) typsicheren Sprachen.
Diese mangelnde Unterstützung durch die Sprache bedeutet, dass Fehler "Null-Fehler" möglicherweise lange Zeit im Programm lauern, bevor sie erkannt werden. Das ist natürlich die Natur von Fehlern, aber es ist bekannt, dass die "Null-Fehler" vermeidbar sind.
Dieses Problem tritt insbesondere in C oder C ++ (zum Beispiel) auf, weil es einen "harten" Fehler verursacht (sofortiger Absturz des Programms ohne elegante Wiederherstellung).
In anderen Sprachen stellt sich immer die Frage, wie man damit umgeht.
In Java oder C # erhalten Sie eine Ausnahme, wenn Sie versuchen, eine Methode für eine Nullreferenz aufzurufen, und dies ist möglicherweise in Ordnung. Und deshalb sind die meisten Java- oder C # -Programmierer daran gewöhnt und verstehen nicht, warum man es anders machen möchte (und lachen über C ++).
In Haskell müssen Sie explizit eine Aktion für den Null-Fall bereitstellen, und daher beklagen sich die Haskell-Programmierer bei ihren Kollegen, weil sie es richtig verstanden haben (richtig?).
Es ist wirklich die alte Debatte um Fehlercode / Ausnahmen, aber diesmal mit einem Sentinel-Wert anstelle von Fehlercode.
Wie immer hängt es von der Situation und der gesuchten Semantik ab, was am besten geeignet ist.
quelle
null
ist wirklich böse, weil es das Typensystem untergräbt . (Zugegeben, die Alternative hat einen Nachteil in ihrer Ausführlichkeit, zumindest in einigen Sprachen.)Sie können keine für Menschen lesbare Fehlermeldung an einen Nullzeiger anhängen.
(Sie können jedoch eine Fehlermeldung in einer Protokolldatei hinterlassen.)
In einigen Sprachen / Umgebungen , die Zeigerarithmetik erlauben, wenn eine der Zeiger Argument null ist , und es wird in die Berechnung erlaubt, wäre das Ergebnis ein sein ungültig , nicht-Null - Zeiger. (*) Mehr Kraft für Sie.
(*) Dies passiert häufig bei der COM- Programmierung. Wenn Sie versuchen, eine Schnittstellenmethode aufzurufen, der Schnittstellenzeiger jedoch Null ist, wird eine ungültige Adresse aufgerufen, die fast, aber nicht ganz genau Null ist.
quelle
Das Zurückgeben von NULL (oder einer numerischen Null oder eines booleschen Fehlers), um einen Fehler anzuzeigen, ist technisch und konzeptionell falsch.
Technisch gesehen belasten Sie den Programmierer mit der sofortigen Überprüfung des Rückgabewerts, genau an dem Punkt, an dem er zurückgegeben wird. Wenn Sie zwanzig Dateien hintereinander öffnen und die Fehlersignalisierung durch die Rückgabe von NULL erfolgt, muss der konsumierende Code jede gelesene Datei einzeln prüfen und aus Schleifen und ähnlichen Konstrukten ausbrechen. Dies ist ein perfektes Rezept für überfüllten Code. Wenn Sie sich jedoch dafür entscheiden, den Fehler durch Auslösen einer Ausnahme zu signalisieren, kann der konsumierende Code entscheiden, die Ausnahme sofort zu behandeln, oder sie auch über Funktionsaufrufe hinweg in beliebig viele Ebenen sprudeln lassen. Dies sorgt für viel saubereren Code.
Wenn Sie eine Datei öffnen und ein Fehler auftritt, ist die Rückgabe eines Werts (sogar NULL) konzeptionell falsch. Sie müssen nichts zurückgeben, da Ihre Operation nicht abgeschlossen wurde. Die Rückgabe von NULL ist die konzeptionelle Entsprechung von "Ich habe die Datei erfolgreich gelesen und hier ist, was sie enthält - nichts". Wenn Sie dies ausdrücken möchten (d. H. Wenn NULL als tatsächliches Ergebnis für die betreffende Operation sinnvoll ist), geben Sie auf jeden Fall NULL zurück. Wenn Sie jedoch einen Fehler signalisieren möchten, verwenden Sie Ausnahmen.
In der Vergangenheit wurden Fehler auf diese Weise gemeldet, da in Programmiersprachen wie C keine Ausnahmebehandlung integriert ist und die empfohlene Methode (mit langen Sprüngen) etwas haarig und kontraintuitiv ist.
Das Problem hat auch eine Wartungsseite: Mit Ausnahmen müssen Sie zusätzlichen Code schreiben, um den Fehler zu beheben. Wenn Sie dies nicht tun, wird das Programm früh und schwer scheitern (was gut ist). Wenn Sie NULL zurückgeben, um Fehler zu signalisieren, ignoriert das Programm standardmäßig den Fehler und setzt den Vorgang fort, bis andere Probleme auftreten - beschädigte Daten, Segfaults, NullReferenceExceptions, abhängig von der Sprache. Um den Fehler früh und laut zu signalisieren, müssen Sie zusätzlichen Code schreiben und raten: Dies ist der Teil, der ausgelassen wird, wenn Sie sich in einer engen Frist befinden.
quelle
Wie bereits erwähnt, konvertieren viele Sprachen eine Dereferenzierung eines Nullzeigers nicht in eine abfangbare Ausnahme. Das ist ein relativ moderner Trick. Als das Nullzeigerproblem zum ersten Mal erkannt wurde, waren noch nicht einmal Ausnahmen erfunden worden.
Wenn Sie Nullzeiger als gültigen Fall zulassen, ist dies ein Sonderfall. Sie benötigen eine spezielle Behandlungslogik, oft an vielen verschiedenen Stellen. Das ist zusätzliche Komplexität.
Unabhängig davon, ob es sich um potenzielle Nullzeiger handelt oder nicht, müssen Sie diese Ausnahmefälle auf eine andere Weise behandeln , wenn Sie keine Ausnahmewürfe zur Behandlung von Ausnahmefällen verwenden. In der Regel muss jeder Funktionsaufruf auf diese Ausnahmefälle überprüft werden, um zu verhindern, dass der Funktionsaufruf unangemessen aufgerufen wird, oder um den Fehlerfall zu erkennen, wenn die Funktion beendet wird. Das ist zusätzliche Komplexität, die durch Ausnahmen vermieden werden kann.
Mehr Komplexität bedeutet normalerweise mehr Fehler.
Alternativen zur Verwendung von Nullzeigern in Datenstrukturen (z. B. zum Markieren des Anfangs / Endes einer verknüpften Liste) umfassen die Verwendung von Sentinel-Elementen. Diese können die gleiche Funktionalität mit einer viel geringeren Komplexität bieten. Es gibt jedoch auch andere Möglichkeiten, die Komplexität zu verwalten. Eine Möglichkeit besteht darin, den potenziellen Nullzeiger in eine Smart Pointer-Klasse einzufügen, sodass die Nullprüfungen nur an einer Stelle erforderlich sind.
Was ist mit dem Nullzeiger zu tun, wenn er erkannt wird? Wenn Sie die Ausnahmebehandlung nicht einbauen können, können Sie immer eine Ausnahme auslösen und diese Sonderfallbehandlung effektiv an den Aufrufer delegieren. Und genau das tun einige Sprachen standardmäßig, wenn Sie einen Nullzeiger dereferenzieren.
quelle
Spezifisch für C ++, aber es null Referenzen gibt es gemieden , weil null Semantik in C ++ mit Zeigertypen zugeordnet sind. Es ist durchaus sinnvoll, dass eine Funktion zum Öffnen von Dateien fehlschlägt und einen Nullzeiger zurückgibt. in der Tat macht die
fopen()
Funktion genau das.quelle
Das hängt von der Sprache ab.
Beispielsweise können Sie mit Objective-C problemlos eine Nachricht an ein Null-Objekt (nil) senden. Ein Aufruf von nil gibt ebenfalls nil zurück und wird als Sprachfunktion betrachtet.
Mir persönlich gefällt es, da Sie sich auf dieses Verhalten verlassen und all diese verschachtelten
if(obj == null)
Konstrukte vermeiden können .Zum Beispiel:
Kann gekürzt werden auf:
Kurz gesagt, es macht Ihren Code besser lesbar.
quelle
Es ist mir egal, ob Sie eine Null zurückgeben oder eine Ausnahme auslösen, solange Sie dies dokumentieren.
quelle
GetAddressMaybe
oderGetSpouseNameOrNull
.Eine Nullreferenz tritt normalerweise auf, weil etwas in der Programmlogik übersehen wurde, dh: Sie sind zu einer Codezeile gekommen, ohne die erforderliche Einrichtung für diesen Codeblock durchzugehen.
Wenn Sie dagegen eine Ausnahme für etwas auslösen, bedeutet dies, dass Sie erkannt haben, dass im normalen Betrieb des Programms eine bestimmte Situation eintreten kann, und dass diese behandelt wird.
quelle
NULL-Referenzen sind oft sehr nützlich: Beispielsweise kann ein Element in einer verknüpften Liste einen Nachfolger oder keinen Nachfolger haben. Die Verwendung
null
für "keinen Nachfolger" ist völlig selbstverständlich. Oder eine Person kann einen Ehepartner haben oder nicht - die Verwendungnull
von "Person hat keinen Ehepartner" ist vollkommen natürlich, viel natürlicher als die Verwendung eines bestimmten "hat keinen Ehepartner" -Sonderwerts, auf den sich dasPerson.Spouse
Mitglied beziehen könnte.Aber: Viele Werte sind nicht optional. In einem typischen OOP-Programm kann nicht mehr als die Hälfte der Referenzen
null
nach der Initialisierung vorhanden sein, da sonst das Programm fehlschlägt. Andernfalls müsste der Code mitif (x != null)
Schecks durchsetzt werden. Warum sollte also jeder Verweis standardmäßig nullbar sein? Es sollte wirklich umgekehrt sein: Variablen sollten standardmäßig nicht nullfähig sein, und Sie sollten explizit "oh, und dieser Wert kannnull
auch" sagen .quelle
Ihre Frage ist verwirrend formuliert. Meinen Sie eine Nullreferenz Ausnahme (die durch einen Versuch tatsächlich dazu gebracht wird, , deReferenz null)? Der eindeutige Grund, diese Art von Ausnahme nicht zu wollen, besteht darin, dass Sie keine Informationen darüber erhalten, was schief gelaufen ist oder sogar wann - der Wert hätte zu jedem Zeitpunkt im Programm auf null gesetzt werden können. Sie schreiben: "Wenn ich Lesezugriff auf eine Datei anfordere, die nicht vorhanden ist, freue ich mich über eine Ausnahme oder einen Nullverweis." Sie sollten sich jedoch nicht über etwas freuen, das keinen Hinweis auf die Ursache enthält . Nirgendwo in der Zeichenfolge "wurde versucht, null zu dereferenzieren" wird das Lesen oder nicht vorhandene Dateien erwähnt. Vielleicht meinen Sie damit, dass Sie sich über den Nullwert als Rückgabewert eines Leseaufrufs sehr freuen würden - das ist eine ganz andere Sache, aber es gibt Ihnen immer noch keine Informationen darüber, warum der Lesevorgang fehlgeschlagen ist. es'
quelle