Ich bin sicher, dass Designer von Sprachen wie Java oder C # Probleme mit der Existenz von Nullreferenzen kannten (siehe Sind Nullreferenzen wirklich eine schlechte Sache? ). Auch das Implementieren eines Optionstyps ist nicht viel komplexer als Nullreferenzen.
Warum haben sie sich überhaupt dafür entschieden? Ich bin sicher, dass das Fehlen von Nullreferenzen sowohl von Sprachentwicklern als auch von Benutzern zu einer besseren Codequalität (insbesondere zu einem besseren Bibliotheksdesign) führen (oder diese sogar erzwingen) würde.
Ist es einfach wegen des Konservativismus - "andere Sprachen haben es, wir müssen es auch haben ..."?
language-design
null
mrpyo
quelle
quelle
Antworten:
Haftungsausschluss: Da ich keinen Sprachdesigner persönlich kenne, ist jede Antwort, die ich Ihnen gebe, spekulativ.
Von Tony Hoare selbst:
Betonung meiner.
Natürlich schien es ihm damals keine schlechte Idee zu sein. Es ist wahrscheinlich, dass es zum Teil aus dem gleichen Grund verewigt wurde - wenn es für den mit dem Turing Award ausgezeichneten Erfinder von Quicksort eine gute Idee war, ist es nicht verwunderlich, dass viele Menschen immer noch nicht verstehen, warum es böse ist. Zum Teil ist dies auch deshalb wahrscheinlich, weil es praktisch ist, wenn neue Sprachen älteren Sprachen ähnlich sind, sowohl aus Marketing- als auch aus Lernkurvengründen. Ein typisches Beispiel:
(Quelle: http://www.paulgraham.com/icad.html )
Und natürlich hat C ++ null, weil C null hat, und es besteht keine Notwendigkeit, auf die historischen Auswirkungen von C einzugehen. C # löste J ++ ab, das die Java-Implementierung von Microsoft war, und C ++ wurde als bevorzugte Sprache für die Windows-Entwicklung abgelöst.
BEARBEITEN Hier ist ein weiteres Zitat von Hoare, das es wert ist, in Betracht gezogen zu werden:
Wieder meine Betonung. Sun / Oracle und Microsoft sind Unternehmen, und das Endergebnis eines Unternehmens ist Geld. Die Vorteile für sie
null
könnten die Nachteile überwiegen, oder sie hatten einfach eine zu enge Frist, um das Problem vollständig zu prüfen. Als Beispiel für einen anderen Sprachfehler, der wahrscheinlich aufgrund von Fristen aufgetreten ist:(Quelle: http://www.artima.com/intv/bloch13.html )
quelle
null
in seiner Sprache implementiert hat ? Jede Antwort auf diese Frage ist spekulativ, es sei denn, sie stammt von einem Sprachdesigner. Ich kenne außer Eric Lippert keine, die diese Seite so häufig besuchen. Der letzte Teil ist aus zahlreichen Gründen ein roter Hering. Die Menge an Code von Drittanbietern, die auf MS- und Java-APIs geschrieben wurde, überwiegt offensichtlich die Menge an Code in der API. Also, wenn Ihre Kunden wollennull
, geben Sie ihnennull
. Sie nehmen auch an, dass sie akzeptiert haben,null
kostet sie Geld.ICloneable
in .NET ähnlich kaputt ist; Leider ist dies ein Ort, an dem die Mängel von Java nicht rechtzeitig gelernt wurden.Na sicher.
Ich bin anderer Ansicht! Die Entwurfsüberlegungen, die in C # 2 zu nullwertfähigen Werttypen führten, waren komplex, kontrovers und schwierig. Sie nahmen den Designteams sowohl der Sprachen als auch der Laufzeit viele Monate Debatte, Implementierung von Prototypen usw. ab, und tatsächlich wurde die Semantik des nullbaren Boxens sehr nahe an Versand C # 2.0 geändert, was sehr umstritten war.
Jedes Design ist ein Prozess der Auswahl unter vielen subtilen und grob inkompatiblen Zielen. Ich kann nur einen kurzen Überblick über einige der Faktoren geben, die berücksichtigt werden sollten:
Die Orthogonalität von Sprachmerkmalen wird im Allgemeinen als eine gute Sache angesehen. C # verfügt über nullfähige Werttypen, nicht nullfähige Werttypen und nullfähige Referenztypen. Nicht nullbare Referenztypen existieren nicht, wodurch das Typensystem nicht orthogonal ist.
Die Kenntnis der vorhandenen Benutzer von C, C ++ und Java ist wichtig.
Einfache Interoperabilität mit COM ist wichtig.
Eine einfache Interoperabilität mit allen anderen .NET-Sprachen ist wichtig.
Eine einfache Interoperabilität mit Datenbanken ist wichtig.
Die Konsistenz der Semantik ist wichtig; Wenn wir den Verweis TheKingOfFrance gleich null haben, heißt das dann immer "es gibt keinen König von Frankreich im Moment", oder heißt das auch "es gibt definitiv einen König von Frankreich; ich weiß nur nicht, wer es im Moment ist"? oder kann es bedeuten, dass "die Vorstellung, einen König in Frankreich zu haben, unsinnig ist, also stell nicht einmal die Frage!"? Null kann all diese Dinge und mehr in C # bedeuten, und all diese Konzepte sind nützlich.
Leistungskosten sind wichtig.
Es ist wichtig, für statische Analysen zugänglich zu sein.
Die Konsistenz des Typsystems ist wichtig; können wir immer wissen , dass ein Nicht-Nullable - Referenz ist nie unter irgendwelchen Umständen beobachtet ungültig sein? Was ist mit dem Konstruktor eines Objekts mit einem nicht nullwertfähigen Referenzfeldtyp? Was ist mit dem Finalizer eines solchen Objekts, bei dem das Objekt finalisiert wird, weil der Code, der den Verweis ausfüllen sollte, eine Ausnahme ausgelöst hat ? Ein Typensystem, das Sie über seine Garantien belügt, ist gefährlich.
Und was ist mit der Konsistenz der Semantik? NULL- Werte werden bei Verwendung weitergegeben, aber NULL- Referenzen lösen bei Verwendung Ausnahmen aus. Das ist inkonsistent; Ist diese Inkonsistenz durch irgendeinen Nutzen gerechtfertigt?
Können wir die Funktion implementieren, ohne andere Funktionen zu beeinträchtigen? Welche anderen möglichen zukünftigen Funktionen schließt die Funktion aus?
Sie ziehen mit der Armee in den Krieg, die Sie haben, nicht mit der, die Sie wollen. Denken Sie daran, dass in C # 1.0 keine Generika vorhanden waren. Daher ist das Sprechen
Maybe<T>
als Alternative ein absoluter Nichtstarter. Sollte .NET für zwei Jahre verrutschen, während das Runtime-Team Generika hinzufügte, nur um Nullreferenzen zu beseitigen?Was ist mit der Konsistenz des Typsystems? Sie können
Nullable<T>
für jeden Werttyp sagen - nein, warten Sie, das ist eine Lüge. Das kannst du nicht sagenNullable<Nullable<T>>
. Solltest du in der Lage sein? Wenn ja, wie lautet die gewünschte Semantik? Lohnt es sich, das gesamte Typensystem nur für diese Funktion mit einem Sonderfall auszustatten?Und so weiter. Diese Entscheidungen sind komplex.
quelle
catches
, tun nichts. Ich denke, es ist besser, das System in die Luft jagen zu lassen, als den Betrieb in einem möglicherweise ungültigen Zustand fortzusetzen.Null dient einem sehr gültigen Zweck, einen Mangel an Wert darzustellen.
Ich werde sagen, dass ich die lautstärkste Person bin, die ich über die Missbräuche von Null und all die Kopfschmerzen und Leiden, die sie verursachen können, weiß, besonders wenn sie großzügig eingesetzt werden.
Mein persönlicher Standpunkt ist, dass Menschen Nullen nur verwenden dürfen , wenn sie begründen können, dass dies notwendig und angemessen ist.
Beispiel zur Begründung von Nullen:
Das Sterbedatum ist in der Regel ein nullwertfähiges Feld. Es gibt drei mögliche Situationen mit Todesdatum. Entweder ist die Person gestorben und das Datum ist bekannt, die Person ist gestorben und das Datum ist unbekannt, oder die Person ist nicht tot und daher gibt es kein Todesdatum.
Das Todesdatum ist auch ein DateTime-Feld und hat keinen "unbekannten" oder "leeren" Wert. Es hat zwar das Standarddatum, das angezeigt wird, wenn Sie eine neue Datumszeit erstellen, die je nach verwendeter Sprache variiert. Technisch gesehen besteht jedoch die Möglichkeit, dass die Person zu diesem Zeitpunkt tatsächlich gestorben ist und als Ihr "leerer Wert" gekennzeichnet wird, wenn Sie dies tun würden Verwenden Sie das Standarddatum.
Die Daten müssten die Situation richtig darstellen.
Person ist verstorben Sterbedatum bekannt (09.03.1984)
Einfach, '3/9/1984'
Person ist Todestag ist unbekannt
Also, was ist am besten? Null , '0/0/0000' oder '01 / 01/1869 '(oder was auch immer Ihr Standardwert ist?)
Person ist nicht tot Sterbedatum ist nicht anwendbar
Also, was ist am besten? Null , '0/0/0000' oder '01 / 01/1869 '(oder was auch immer Ihr Standardwert ist?)
Denken wir also über jeden Wert nach ...
Die Tatsache , manchmal Sie Sie brauchen nichts zu vertreten und sicher manchmal ein Variablentyp eignet sich gut für das, aber oft Variablentypen müssen in der Lage sein , nichts zu vertreten.
Wenn ich keine Äpfel habe, habe ich 0 Äpfel, aber was ist, wenn ich nicht weiß, wie viele Äpfel ich habe?
Auf jeden Fall ist null missbraucht und möglicherweise gefährlich, aber es ist manchmal notwendig. In vielen Fällen ist dies nur die Standardeinstellung, denn bis ich einen Wert gebe, fehlt ein Wert und etwas muss ihn darstellen. (Null)
quelle
Null serves a very valid purpose of representing a lack of value.
EinOption
oderMaybe
-Typ erfüllt diesen sehr gültigen Zweck, ohne das Typensystem zu umgehen.NOT NULL
. Meine Frage hatte jedoch nichts mit RDBMS zuPerson
Typ hat einstate
TypfeldState
, das eine diskriminierte Vereinigung vonAlive
und istDead(dateOfDeath : Date)
.Ich würde nicht so weit gehen, wie "andere Sprachen es haben, wir müssen es auch haben ...", als wäre es eine Art Schritt mit den Joneses. Ein wichtiges Merkmal jeder neuen Sprache ist die Fähigkeit, mit vorhandenen Bibliotheken in anderen Sprachen zusammenzuarbeiten (siehe: C). Da C Nullzeiger hat, muss für die Interoperabilitätsschicht unbedingt das Konzept von Null gelten (oder ein anderes "nicht vorhandenes" Äquivalent, das bei Verwendung explodiert).
Die Sprache Designer könnten haben gewählt verwenden Option - Typen und zwingen Sie den Null - Pfad zu behandeln überall , dass die Dinge null sein könnten. Und das würde mit ziemlicher Sicherheit zu weniger Fehlern führen.
Die Verwendung von Optionstypen für diese Interoperabilitätsschicht hätte jedoch (insbesondere für Java und C # aufgrund des Zeitpunkts ihrer Einführung und ihrer Zielgruppe) wahrscheinlich geschadet, wenn ihre Annahme nicht torpediert worden wäre. Entweder wird der Optionstyp komplett durchgereicht, was die C ++ - Programmierer der mittleren bis späten 90er-Jahre nervt - oder die Interoperabilitätsschicht wirft Ausnahmen, wenn sie auf Nullen stößt, was die C ++ - Programmierer der mittleren bis späten 90er-Jahre nervt. ..
quelle
Option
für die Verwendung in Scala zu packen, was so einfach ist wieval x = Option(possiblyNullReference)
. In der Praxis dauert es nicht lange, bis die Menschen die Vorteile einesOption
.Match
Methode zu fälschen , die Delegaten als Argumente verwendet. Dann übergeben Sie Lambda-Ausdrücke anMatch
(Bonuspunkte für die Verwendung benannter Argumente) undMatch
rufen die richtige auf.Ich denke, wir sind uns alle einig, dass ein Konzept der Nichtigkeit notwendig ist. Es gibt Situationen, in denen wir das Fehlen von Informationen darstellen müssen.
Das Zulassen von
null
Referenzen (und Zeigern) ist nur eine Implementierung dieses Konzepts und möglicherweise die beliebteste, obwohl Probleme bekannt sind: C, Java, Python, Ruby, PHP, JavaScript usw. verwenden alle ein ähnliches Konzeptnull
.Warum ? Nun, was ist die Alternative?
In funktionalen Sprachen wie Haskell haben Sie den Typ
Option
oderMaybe
; diese bauen jedoch auf:Hat das ursprüngliche C, Java, Python, Ruby oder PHP eine dieser Funktionen unterstützt? Nein. Javas fehlerhafte Generika sind neu in der Geschichte der Sprache und ich bezweifle irgendwie, dass die anderen sie überhaupt implementieren.
Hier hast du es.
null
ist einfach, parametrische algebraische Datentypen sind schwieriger. Die Leute entschieden sich für die einfachste Alternative.quelle
Object
", erkennen nicht, dass praktische Anwendungen nicht gemeinsam genutzte veränderbare Objekte und gemeinsam nutzbare unveränderliche Objekte (die sich beide wie Werte verhalten sollten) sowie gemeinsam nutzbare und nicht gemeinsam nutzbare Objekte benötigen Entitäten. Die Verwendung eines einzigenObject
Typs für alles macht solche Unterscheidungen nicht überflüssig. es macht es nur schwieriger, sie richtig zu verwenden.Null / nil / none selbst ist nicht böse.
Wenn Sie seine irreführenden Namen berühmte Rede Schau „Milliarden - Dollar - Fehler“, Tony Hoare spricht darüber , wie so dass jede Variable der Lage sein , null zu halten , war ein großer Fehler. Die Alternative - mit Optionen - nicht nicht in der Tat von null Referenzen loszuwerden. Stattdessen können Sie angeben, welche Variablen null enthalten dürfen und welche nicht.
Tatsächlich unterscheiden sich Null-Dereferenzierungsfehler bei modernen Sprachen, die eine ordnungsgemäße Ausnahmebehandlung implementieren, nicht von anderen Ausnahmen - Sie finden sie, Sie beheben sie. Einige Alternativen zu Null-Referenzen (zum Beispiel das Null-Objekt-Muster) verbergen Fehler und führen dazu, dass Dinge erst viel später stillschweigend fehlschlagen. Meiner Meinung nach ist es viel besser, schnell zu scheitern .
Die Frage ist also, warum Sprachen Optionen nicht implementieren können. Tatsächlich kann die wohl beliebteste Sprache aller Zeiten in C ++ Objektvariablen definieren, die nicht zugewiesen werden können
NULL
. Dies ist eine Lösung für das "Null-Problem", das Tony Hoare in seiner Rede erwähnte. Warum hat die am weitesten verbreitete Schriftsprache Java sie nicht? Man könnte fragen, warum es im Allgemeinen so viele Mängel hat , insbesondere in seinem Typensystem. Ich glaube nicht, dass man wirklich sagen kann, dass Sprachen diesen Fehler systematisch begehen. Manche tun es, manche nicht.quelle
null
.null
ist die einzig sinnvolle Standardeinstellung für Variablen vom Referenztyp, die zum Einkapseln der Identität verwendet werden . Referenzen, die zum Einkapseln von Werten verwendet werden, können jedoch in Fällen, in denen ein Typ eine sinnvolle Standardinstanz haben würde oder konstruieren könnte, ein sinnvolles Standardverhalten aufweisen. Viele Aspekte, wie sich Referenzen verhalten sollten, hängen davon ab, ob und wie sie den Wert verkapseln, aber ...foo
der einzige Verweis auf einint[]
Containing ist{1,2,3}
und Codefoo
einen Verweis auf einint[]
Containing enthalten{2,2,3}
möchte, ist das Inkrementieren der schnellste Weg, dies zu erreichenfoo[0]
. Wenn Code einer Methode mitteilen möchte, dass siefoo
gültig ist{1,2,3}
, ändert die andere Methode das Array nicht und behält einen Verweis nicht über den Punkt hinaus beifoo
, an dem er geändert werden soll. Der schnellste Weg, dies zu erreichen, besteht darin, einen Verweis an das Array zu übergeben. Wenn Java einen "ephemeren Nur-Lese-Verweistyp" hatte, dann ...Denn Programmiersprachen sind in der Regel eher praktisch als technisch korrekt. Tatsache ist, dass
null
Zustände aufgrund von fehlerhaften oder fehlenden Daten oder aufgrund eines noch nicht festgelegten Zustands häufig vorkommen. Die technisch überlegenen Lösungen sind umso unhandlicher, als Nullzustände zuzulassen und die Tatsache, dass Programmierer Fehler machen, in den Hintergrund zu rücken.Wenn ich zum Beispiel ein einfaches Skript schreiben möchte, das mit einer Datei funktioniert, kann ich Pseudocode wie folgt schreiben:
und es wird einfach fehlschlagen, wenn joebloggs.txt nicht existiert. Die Sache ist, dass für einfache Skripte, die wahrscheinlich in Ordnung sind, und für viele Situationen in komplexerem Code ich weiß, dass sie existieren und der Fehler nicht auftreten wird, was mich dazu zwingt, meine Zeit zu verschwenden. Die sichereren Alternativen erreichen ihre Sicherheit, indem sie mich zwingen, richtig mit dem potenziellen Ausfallstatus umzugehen, aber oft möchte ich das nicht, ich möchte einfach weiter.
quelle
for line in file
) fortgesetzt und eine bedeutungslose Nullreferenzausnahme ausgelöst. Dies ist für ein so einfaches Programm in Ordnung, verursacht jedoch echte Fehlerbehebungsprobleme in viel komplexeren Systemen. Wenn es keine Nullen gäbe, könnte der Designer von "openfile" diesen Fehler nicht machen.let file = something(...).unwrap()
. Abhängig von Ihrem POV ist es eine einfache Möglichkeit, Fehler oder eine prägnante Behauptung, dass Null nicht auftreten kann, zu vermeiden. Die Zeit verschwendet ist minimal, und Sie Zeit an anderen Orten sparen , weil Sie nicht aus Figur haben, ob etwas kann null sein. Ein weiterer Vorteil (der für sich genommen den zusätzlichen Aufruf wert sein kann) ist, dass Sie den Fehlerfall explizit ignorieren. Wenn es fehlschlägt, gibt es kaum Zweifel, was schief gelaufen ist und wo das Update hin muss.if file exists { open file }
leidet unter einer Racebedingung . Die einzige zuverlässige Methode, um festzustellen, ob das Öffnen einer Datei erfolgreich ist, besteht darin, sie zu öffnen.Der Zeiger
NULL
(odernil
oderNil
odernull
oderNothing
oder was auch immer in Ihrer bevorzugten Sprache genannt wird) kann eindeutig und praktisch verwendet werden .Für Sprachen ohne Ausnahmesystem (z. B. C) kann ein Nullzeiger als Fehlermarke verwendet werden, wenn ein Zeiger zurückgegeben werden soll. Zum Beispiel:
Hier wird ein
NULL
zurückgegebener vonmalloc(3)
als ein Marker des Scheiterns verwendet.Wenn es in Methoden- / Funktionsargumenten verwendet wird, kann es den Standardwert für das Argument angeben oder das Ausgabeargument ignorieren. Beispiel unten.
Selbst für Sprachen mit Ausnahmemechanismus kann ein Nullzeiger als Hinweis auf einen weichen Fehler verwendet werden (dh auf Fehler, die behoben werden können), insbesondere wenn die Ausnahmebehandlung teuer ist (z. B. Objective-C):
In diesem Fall führt der Soft-Fehler nicht zum Absturz des Programms, wenn er nicht abgefangen wird. Dies beseitigt den verrückten Try-Catch, den Java hat, und hat eine bessere Kontrolle über den Programmfluss, da weiche Fehler nicht unterbrochen werden (und die wenigen verbleibenden harten Ausnahmen sind normalerweise nicht behebbar und bleiben unberührt).
quelle
null
von denen zu unterscheiden, die enthalten sollten. Wenn ich zum Beispiel einen neuen Typ möchte, der 5 Werte in Java enthält, könnte ich eine Aufzählung verwenden, aber was ich erhalte, ist ein Typ, der 6 Werte enthalten kann (die 5, die ich wollte +null
). Es ist ein Fehler im Typensystem.Null
kann nur dann eine Bedeutung zugewiesen werden, wenn die Werte eines Typs keine Daten enthalten (z. B. Aufzählungswerte). Sobald Ihre Werte etwas komplizierter sind (z. B. eine Struktur),null
kann keine für diesen Typ sinnvolle Bedeutung zugewiesen werden. Es gibt keine Möglichkeit, anull
als Struktur oder Liste zu verwenden. Und das Problem bei der Verwendungnull
als Fehlersignal ist wiederum, dass wir nicht sagen können, was null zurückgeben oder null akzeptieren könnte. Jede Variable in Ihrem Programm kann eine Variable sein,null
es sei denn, Sie überprüfen jede einzelne Variablenull
vor jeder einzelnen Verwendung mit äußerster Sorgfalt , was niemand tut.null
als verwendbaren Standardwert zu betrachten (z. B. den Standardwert "string
Verhalten als leere Zeichenfolge" wie im vorherigen Common Object Model). Alles, was nötig gewesen wäre, wäre gewesen, dass Sprachen verwendet würden,call
anstattcallvirt
nicht-virtuelle Mitglieder aufzurufen.Es gibt zwei verwandte, aber leicht unterschiedliche Probleme:
null
es überhaupt geben? Oder solltest du immer verwenden,Maybe<T>
wo null nützlich ist?Sollten alle Referenzen nullbar sein? Wenn nicht, welche sollte die Standardeinstellung sein?
Wenn nullbare Verweistypen explizit als
string?
oder ähnlich deklariert werden müssen, werden die meisten (aber nicht alle) Problemenull
vermieden, ohne sich zu stark von den Programmierern zu unterscheiden, an die sie gewöhnt sind.Ich stimme Ihnen zumindest zu, dass nicht alle Verweise nullwertfähig sein sollten. Aber die Vermeidung von Null ist nicht ohne Komplexität:
.NET initialisiert alle Felder auf,
default<T>
bevor verwalteter Code zum ersten Mal auf sie zugreifen kann. Dies bedeutet, dass Sie für Referenztypennull
oder etwas Äquivalentes Werttypen auf eine Art von Null initialisieren können, ohne Code auszuführen. Während beide schwerwiegende Nachteile haben, hat die Einfachheit derdefault
Initialisierung diese Nachteile möglicherweise überwogen.Zum Beispiel Feldern können Sie durch die Forderung der Initialisierung von Feldern dieses Problem umgehen , bevor der Belichtungs
this
Zeiger auf verwalteten Code. Spec # ist diesen Weg gegangen und hat im Vergleich zu C # eine andere Syntax als die Konstruktorkettung verwendet.Stellen Sie bei statischen Feldern sicher, dass dies schwieriger ist, es sei denn, Sie schränken die Ausführung von Code in einem Feldinitialisierer stark ein, da Sie den
this
Zeiger nicht einfach ausblenden können .Wie initialisiere ich Arrays von Referenztypen? Betrachten Sie ein,
List<T>
das durch ein Array mit einer Kapazität größer als die Länge gesichert ist. Die übrigen Elemente , müssen sie etwas Wert.Ein weiteres Problem ist, dass Methoden wie "
bool TryGetValue<T>(key, out T value)
which return" nicht zugelassen werden,default(T)
alsvalue
ob sie nichts finden würden. In diesem Fall ist es jedoch leicht zu argumentieren, dass der out-Parameter in erster Linie ein schlechtes Design ist und diese Methode eine diskriminierende Union oder ein Vielleicht zurückgeben sollte.All diese Probleme können gelöst werden, aber es ist nicht so einfach wie "Null verbieten und alles ist in Ordnung".
quelle
List<T>
ist meiner Meinung nach das beste Beispiel, denn es würde entweder erfordern , dass jederT
einen Standardwert haben, dass jedes Element in dem Zusatzspeicher sein einMaybe<T>
mit einem zusätzlichen „isValid“ Feld, auch wennT
einMaybe<U>
oder dass der Code für dieList<T>
verhalten sich unterschiedlich , je obT
es sich um einen nullbaren Typ handelt. Ich würde Initialisierung der berücksichtigenT[]
Elemente auf einen Standardwert das kleinste Übel dieser Entscheidungen sein, aber es natürlich bedeutet , dass die Elemente zu benötigen haben einen Standardwert.Die meisten nützlichen Programmiersprachen ermöglichen das Schreiben und Lesen von Datenelementen in willkürlichen Sequenzen, so dass es häufig nicht möglich ist, die Reihenfolge der Lese- und Schreibvorgänge vor dem Ausführen eines Programms statisch zu bestimmen. Es gibt viele Fälle, in denen Code tatsächlich nützliche Daten in jedem Slot speichert, bevor er gelesen wird, aber es schwierig ist, dies zu beweisen. Daher ist es häufig erforderlich, Programme auszuführen, bei denen es zumindest theoretisch möglich ist, dass der Code versucht, etwas zu lesen, das noch nicht mit einem nützlichen Wert geschrieben wurde. Unabhängig davon, ob dies für Code zulässig ist oder nicht, gibt es keine allgemeine Möglichkeit, den Versuch von Code zu stoppen. Die Frage ist nur, was passieren soll, wenn das passiert.
Unterschiedliche Sprachen und Systeme verfolgen unterschiedliche Ansätze.
Ein Ansatz wäre zu sagen, dass jeder Versuch, etwas zu lesen, das nicht geschrieben wurde, einen sofortigen Fehler auslöst.
Ein zweiter Ansatz besteht darin, dass Code an jeder Stelle einen Wert bereitstellen muss, bevor er gelesen werden kann, auch wenn der gespeicherte Wert semantisch nicht sinnvoll wäre.
Ein dritter Ansatz besteht darin, das Problem einfach zu ignorieren und alles "natürlich" geschehen zu lassen.
Ein vierter Ansatz ist zu sagen, dass jeder Typ einen Standardwert haben muss, und jeder Slot, der nicht mit etwas anderem geschrieben wurde, wird standardmäßig auf diesen Wert gesetzt.
Ansatz 4 ist weitaus sicherer als Ansatz 3 und im Allgemeinen billiger als Ansatz 1 und 2. Dann bleibt die Frage, wie der Standardwert für einen Referenztyp lauten soll. Für unveränderliche Referenztypen ist es in vielen Fällen sinnvoll, eine Standardinstanz zu definieren und zu sagen, dass der Standard für jede Variable dieses Typs ein Verweis auf diese Instanz sein sollte. Für veränderbare Referenztypen wäre dies jedoch nicht sehr hilfreich. Wenn versucht wird, einen veränderlichen Referenztyp zu verwenden, bevor er geschrieben wurde, gibt es im Allgemeinen keine sichere Vorgehensweise, außer zum Zeitpunkt des Verwendungsversuchs zu fangen.
Semantisch gesehen, wenn man ein Array
customers
vom TypCustomer[20]
hat und es versucht,Customer[4].GiveMoney(23)
ohne etwas gespeichert zu habenCustomer[4]
, muss die Ausführung abfangen. Man könnte argumentieren, dass einCustomer[4]
Leseversuch sofort abfangen sollte, anstatt zu warten, bis der Code versuchtGiveMoney
, aber es gibt genügend Fälle, in denen es nützlich ist, einen Slot zu lesen, herauszufinden, dass er keinen Wert enthält, und diesen dann zu nutzen Informationen, die besagen, dass der Leseversuch selbst fehlschlägt, sind oft ein großes Ärgernis.In einigen Sprachen kann angegeben werden, dass bestimmte Variablen niemals Null enthalten dürfen, und jeder Versuch, eine Null zu speichern, sollte einen sofortigen Trap auslösen. Das ist eine nützliche Funktion. Im Allgemeinen muss jedoch jede Sprache, die es Programmierern ermöglicht, Arrays von Referenzen zu erstellen, entweder die Möglichkeit von Null-Array-Elementen zulassen oder die Initialisierung von Array-Elementen auf Daten erzwingen, die möglicherweise nicht aussagekräftig sind.
quelle
Maybe
/Option
type das Problem mit # 2 nicht lösen, da Sie, wenn Sie noch keinen Wert für Ihre Referenz haben, aber in Zukunft einen haben werden, diesen einfachNothing
in einem speichern könnenMaybe <Ref type>
?null
richtig / sinnvoll zu verwenden?List<T>
aT[]
oder a seinMaybe<T>
? Was ist mit dem Backing-Typ einesList<Maybe<T>>
?Maybe
Sinn macht,List
da erMaybe
einen einzelnen Wert enthält. Meinten SieMaybe<T>[]
?Nothing
kann nur Werten vom Typ zugewiesen werdenMaybe
, es ist also nicht ganz wie beim Zuweisennull
.Maybe<T>
undT
sind zwei verschiedene Typen.