![]() |
Spring4D: Nullables
Eine Verständnisfrage zu
![]() ![]()
Delphi-Quellcode:
Der Compiler hat nichts dagegen, einem
procedure test();
var numberValue: Spring.Nullable<Integer>; begin numberValue := 99.0; numberValue := TObject.Create(); end;
Delphi-Quellcode:
praktisch alles mögliche zuzuweisen. Das liegt daran, dass für ein Nullable eine implizite Operator-Überladung für
Nullable<Integer>
Delphi-Quellcode:
definiert ist:
Variant
Delphi-Quellcode:
class operator Implicit(const value: Variant): Nullable<T>;
Kritik an Spring4D kann ich mir nicht erlauben, aber ich finde das schrecklich. Warum sollte man so etwas wollen? Zwischen
Delphi-Quellcode:
und
Nullable<T>
Delphi-Quellcode:
hin und her ist klar, aber warum Variant zu Nullable<T> generell erlauben?
T
|
AW: Spring4D: Nullables
Weil du dann aus einer Datenbank die Werte direkt zuweisen kannst und ein
Delphi-Quellcode:
-Wert dann korrekt zugewiesen wird.
NULL
Im Übrigen kann man eine Referenz durchaus einem
Delphi-Quellcode:
zuweisen ;)
Integer
Was nicht gehen sollte ist
Delphi-Quellcode:
var
ni : Nullable<Integer>; ni := 'Moin'; |
AW: Spring4D: Nullables
Delphi-Quellcode:
sollte aber auch nicht gehen.
ni := TObject.Create()
|
AW: Spring4D: Nullables
Gerade mal eben geschaut, es liegt nicht an den Variants, sondern an
Delphi-Quellcode:
type
Nullable<T> = record // ... class operator Implicit(value: Pointer): Nullable<T>; // Übeltäter // ... end; |
AW: Spring4D: Nullables
Zitat:
Zitat:
Delphi-Quellcode:
schreiben kann.
meinNullable := nil
Über die Nützlichkeit und die möglichen Auswirkungen davon kann man gerne diskutieren. Aber wenn man das nicht mag, auskommentieren, glücklich sein. Das ist ja das schöne an open Source, gell? :) |
AW: Spring4D: Nullables
Klar, das mit dem
Delphi-Quellcode:
ist natürlich viel komfortabler als irgendein Hickhack mit vielleicht
:= nil
Delphi-Quellcode:
oder sowas.
TNullable<Integer>.Empty
Aber mit dem Variant-Gedöns kann ich mich wirklich nicht anfreunden. Die ganze Typsicherheit geht einem doch da den Bach runter. War die Intention denn von Anfang an, das mit
Delphi-Quellcode:
-Objekten kompatibel zu machen? Wenn ja, dann wäre ein eigener Typ
TField
Delphi-Quellcode:
oder sowas besser.
TFieldContent<T>
Auskommentieren und Spring neu kompilieren habe ich mich noch nicht getraut, ich hätte spontan erwartet dass Spring die Nullables dann selbst irgendwo so benutzt und ihm diese Operator-Überladung dann fehlt... |
AW: Spring4D: Nullables
Dein eingangs beschriebenes Problem liegt einzig und allein an dem Pointer overload, den ich aber in Rücksprache mit meinem Kollegen für 1.2 entfernen werde.
Immerhin kann man ja
Delphi-Quellcode:
schreiben, was exakt dieselbe Auswirkung hat, nur ohne die negativen Seiteneffekte, dass ich sämtliche Referenztypes assignen kann.
:= Null
Nullable<T> <-> Variant Kompatibilität ist explizites Feature. Allerdings werden auch nur Variants akzeptiert, die direkt den zu T passenden Typen haben. Das hier geht also nicht:
Delphi-Quellcode:
Kompiliert zwar (sorry!) aber wirft zur Laufzeit ein EInvalidCast.
myIntNullable := '5';
|
AW: Spring4D: Nullables
Würdet ihr euch denn dazu überreden lassen der
Delphi-Quellcode:
-Property dann einen Setter zu verpassen damit man, wenn man will, zur Compile-Zeit ein bisschen Typsicherheit hat?
Value
Wenn die Pointer-Überladung rausfällt, bekommt ein Nullable dann eine
Delphi-Quellcode:
-Methode oder wie löscht man den?
Clear()
|
AW: Spring4D: Nullables
Zitat:
Überleg mal, was sonst mit solchem Code passiert:
Delphi-Quellcode:
Da Nullable<T> ein Record ist, würdest du nämlich dann nur die lokale Kopie verändern.
myObj.NullableIntProp.Value := 42;
... siehe ![]() Zitat:
Delphi-Quellcode:
Außerdem könnte man sonst eine readonly nullable Eigenschaft nicht vor Modifikation schützen können.
x := Null;
... |
AW: Spring4D: Nullables
Bitter, da habe ich auf die Schnelle nicht dran gedacht.
Trotzdem macht mir
Delphi-Quellcode:
Angst. Ist mir neulich zum ersten mal zur Laufzeit um die Ohren geflogen und jetzt frage ich mich die ganze Zeit wie ich noch solche Stellen finden kann...
myNullableInteger := 'Wurst'
|
AW: Spring4D: Nullables
Zitat:
Wir machen uns mal Gedanken dazu :gruebel: Eine Möglichkeit, die mir spontan einfällt, wäre den implicit operator für Variant->Nullable<T> auf explicit zu ändern. Dann muss man einen Hardcast schreiben:
Delphi-Quellcode:
P.S. Näää, vergisset, dat geht nich -.- Dann würde bei (*) wieder die Variant to T konvertierung zuschlagen und möglicherweise strings in Integer casten und die in den Nullable packen oder EVariantTypeCastError werfen, wenn null drin steckt. :(
myNullableInteger := 'Wurst'; // kompiliert nicht
myNullableInteger := Nullable<Integer>('Wurst'); // kompiliert aber wie gehabt Exception myNullableInteger := myVariant; // kompiliert nicht mehr - breaking change (*) myNullableInteger := Nullable<Integer>(myVariant); // kompiliert und wie bisher je nachdem, was im Variant drin steckt erfolgreich oder Exception |
AW: Spring4D: Nullables
Ich habe in meiner Bibliothek auch einen Nullable-Typen und da gibt es zusätzlich einen
Delphi-Quellcode:
Dafür habe ich zwar keine Variants-Unterstützung, aber immer eine Typsichere Zuweisung :stupid:
type
Nullable = record const NULL : Nullable; end; type Nullable<T> = record public class operator implicit( const Value : Nullable ): Nullable<T>; end; Hübsch finde ich es auch noch
Delphi-Quellcode:
Hübsch fand ich auch noch die Abkürzungen (damit meine zarten Finger geschont werden :mrgreen:)
var
ni : Nullable<Integer>; begin ni := 5; ni := Nullable.Null; // auf NULL prüfen if ni = Nullable.Null then begin end; // auf NULL prüfen if not ni.HasValue then begin end; end;
Delphi-Quellcode:
NullableInteger = Nullable<Integer>;
NInteger = NullableInteger; |
AW: Spring4D: Nullables
Zitat:
Zitat:
|
AW: Spring4D: Nullables
Zitat:
Zitat:
|
AW: Spring4D: Nullables
Zitat:
Mein Vorschlag
Dann könnte man schreiben
Delphi-Quellcode:
var
myNullableInt: Spring.Nullable<T> ... myNullableInt := myQuery.FieldByName('MY_FELD').AsNullable<Integer>; // alternative Syntax myNullableInt := myQuery.NullableField<Integer>('MY_FELD'); |
AW: Spring4D: Nullables
Ich verstehe eins hierbei noch nicht:
Warum ist denn die Variant-Geschichte eigentlich Implicit und nicht Explicit? Wäre Sie es, kann ich immer noch sagen
Delphi-Quellcode:
oder
myNullableInt := myDatabaseField.Value
Delphi-Quellcode:
myNullableInt := myStrangeVariant
Ich kann allerdings nicht mehr sagen
Delphi-Quellcode:
myNullableInt := myFloatValue
|
AW: Spring4D: Nullables
Wenn also Nullables beliebigen Typs sein können, wieso verwende ich nicht dann einfach Variants?
|
AW: Spring4D: Nullables
Zitat:
Delphi-Quellcode:
soll eben nicht alles beinhalten, sondern typsicher einen Wert vom Typ
Nullable<T>
Delphi-Quellcode:
oder eben nichts.
T
|
AW: Spring4D: Nullables
Zitat:
Also so:
Delphi-Quellcode:
oder
myNullableInt := Nullable<Integer>(myDatabaseField.Value);
Delphi-Quellcode:
myNullableInt := Nullable<Integer>(myStrangeVariant)
|
AW: Spring4D: Nullables
Zitat:
Delphi-Quellcode:
auch einen String zuweisen kann, ohne das es knallt (also eher 'ein bisschen typsicher'). Und das der Wert dann 0 ist.
Nullable<Integer>
Na ja. Ein etwas besseres 'VarToInt' (aka convert) tut's ja auch. Also: Ich weise einem Variant zu, was ich will und erst beim Auslesen interpretiere ich, was da drin steht. Hmm. Vom Verhalten sehe ich jetzt nicht so den Unterschied zu normalen Variants, aber egal. |
AW: Spring4D: Nullables
Zitat:
Delphi-Quellcode:
. Das will man im Endeffekt doch.
myDatabaseField.Value
Oder ist es tatsächlich, wie Dejan Vu meint, nur als eine andere Schreibweise für Variants gedacht?
Delphi-Quellcode:
erlaubt:
class operator Explicit(const from: Variant): Nullable<T>;
class operator Implicit(const from: T): Nullable<T>;
Delphi-Quellcode:
var
myWrapper: TWrapper<Integer>; myVariant: Variant; begin myWrapper := 42; //myWrapper := 'Hallo'; // nope myWrapper := Variant('Hallo'); // oder myVariant := 'Hallo'; myWrapper := myVariant; end. |
AW: Spring4D: Nullables
TField.Value ist ein Variant. Und wenn man AsX (X sei der Typ des Felds, also string, Integer o.Ä.) führt bei Null zu einem Fehler. Daher gibts den Overload für Variant, so dass der Variant nicht erst in eine Null exception läuft sondern das "auspacken" dem Nullable überlässt.
Und nein, ein Nullable ist kein Variant! In einen Variant kann ich zur Laufzeit alles (*) reinpacken und der Variant ist fröhlich. In einen Nullable geht nur T oder ein Variant (wobei der Variant auch nur einen T beinhalten darf, es wird hier keine Konvertierung durchgeführt). Dass das nunmal nicht zur Compiletime geht liegt daran, dass es nicht im Compiler eingebaut ist. Dafür musst du dich an Embarcadero wenden. (*) was in einen Variant passt Wenn du in deinem Code die stellen aufdecken willst, die den Variant overload nutzen, dann schlag ich vor, pack nen deprecated an diesen Overload und du siehst beim Kompilieren jede Stelle, die den nutzt. |
AW: Spring4D: Nullables
Zitat:
Delphi-Quellcode:
eben kein
Nullable<Integer>
Delphi-Quellcode:
zugewiesen werden. Mein
string
Delphi-Quellcode:
hat auch keinen impliziten Cast von einem
Nullable<T>
Delphi-Quellcode:
, denn nach meinem Verständnis soll ein
Variant
Delphi-Quellcode:
eben nicht alles beinhalten, sondern typsicher den angegebenen Typen
Nullable<T>
Delphi-Quellcode:
oder eben nichts.
T
Genau das steht auch schon in meinen Beiträgen hier ... Und wie immer ist dieses Konstrukt einfach nur zum Vereinfachen gedacht:
Delphi-Quellcode:
var
a,b,c : Nullable<Integer>; d : Integer; begin a := Nullable.Null; b := 42; c := a+b; // c => Null d := a.ValueOrDefault() + b.ValueOrDefault(); // d => 42 end; |
AW: Spring4D: Nullables
Dann mach doch deinen Nullable open Source, Günther kann ihn nutzen und wir ersparen uns die ewige Im-Kreis-Dreherei. :roll:
P.S. Was macht eigtl dein Add overload bei Typen, bei denen es keine Addition gibt? |
AW: Spring4D: Nullables
Lass uns noch ein bisschen drehen :spin2:
Ein bisschen. Zitat:
Ist es explizit, kann man weiterhin alle
Delphi-Quellcode:
reinstecken. Oder
TField.Value
Delphi-Quellcode:
. Oder was auch immer. Was würde man dadurch verlieren?
IXMLNode.Value
|
AW: Spring4D: Nullables
Zitat:
|
AW: Spring4D: Nullables
Zitat:
Der Fakt, dass ein string in einen Variant gecastet wird und dann an den Variant Overload übergeben wird, hat nix mit dem Overload zu tun, sondern damit, wie Variants funktionieren. Zitat:
![]() |
AW: Spring4D: Nullables
Zitat:
Seitdem ich Nullables in C# entdeckt habe, trauere ich den Variants hinterher. Auf der anderen Seite brauche ich sie eigentlich nie. |
AW: Spring4D: Nullables
Zitat:
Wenn einem die eine oder andere Funktionalität nicht zusagt, dann kommentiert man die einfach aus (Open Source lässt grüßen). Mein Beitrag hierzu war den Grund zu erläutern, warum es so einen Variant Cast gibt - ich persönlich den aber nicht mag - und wie ich es bei mir persönlich gelöst habe, um eine Alternative aufzuzeigen. Das nennt man dann Austausch von Gedanken und Erfahrungen. Mag seltsam klingen, mir aber egal. |
AW: Spring4D: Nullables
Sag mal, hast Du Anteile an Bold-Schriften erworben oder wieso spickst Du deine Ausführungen ständig damit?
Das fette 'Mein..Meine...meins' Zitat sollte eher darauf hinweisen, das man es mit der Betonung der EIGENEN Meinung auch ÜBERTREIBEN kann, ABER DAS SCHEINT NICHT ANGEKOMMEN ZU SEIN !!!!!11!!!!11!1!EINS!!!1!!ELF!!! Wink. Zaun. Pfahl. Netiquette. Blinzel. Knick-Knack. Say No more. |
AW: Spring4D: Nullables
Lange hat's gedauert, aber ich hab wohl endlich
![]() |
AW: Spring4D: Nullables
Lange hatte ich es auf meiner "Demnächst lesen"-Liste, jetzt gelesen und ich musste lachen :-D
Coole Idee :thumb: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:44 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz