![]() |
[Variants] 0 = Unassigned, wieso das denn?
Hi,
ich arbeite mal wieder mit Variants und dabei kriege ich wegen folgendem Bug ne Krise:
Delphi-Quellcode:
Was glaubt Ihr, zeigt mein Delphi? Genau! angeblich ist "0 = Unassigned". Kann mir mal einer den Müll erklären?
Var
v : Variant; begin v := 0; if v = Unassigned then ShowMessage('Delphi ist (Del)phies'); end; Klappt mit D6E und BDS2006, ich könnte :kotz: |
Re: [Variants] 0 = Unassigned, wieso das denn?
Moin alzaimar,
das halte ich mal für einen Bug. Immerhin ist auch NULL <> unassigned ;-) Wenn Du mit NULL vergleichst klappt es. |
Re: [Variants] 0 = Unassigned, wieso das denn?
Ich prüfe das immer so:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var v : Variant; i : Integer; begin i := 0; v := i; if VarIsNull (v) or VarIsEmpty (v) then ShowMessage ('Unassigned'); v := Unassigned; end; |
Re: [Variants] 0 = Unassigned, wieso das denn?
Ahoj,
so sehe ich das auch, nur ist der Bug schon seit 317 Jahren im System. Der Fehler liegt in der schlampigen Programmierung der VarCompareSimple: Dort wird aus Unassigned einfach der korrespondierende 0-Wert des zweiten Variants. Hier müsste man vorher prüfen, ob entweder die linke oder die rechte Seite 'UnAssigned' ist und dann sofort False liefern, denn ein Vergleich mit unassigned liefert immer False (außer mit Unassigned selbst). Na ja, Schlampen halt :mrgreen: iKilledKenny: Danke für den Workaround, nur ist nicht 100% korrekt, den Null != Unassigned, Du machst aber keinen Unterschied (ich denke aber, das Dir das egal ist). |
Re: [Variants] 0 = Unassigned, wieso das denn?
Der Workaround klappt sehr wohl.
VarIsEmpty == (v = Unassigned) VarIsNull == (v = NULL) |
Re: [Variants] 0 = Unassigned, wieso das denn?
Hatten wir nicht neulich schon mal was ähnliches? Mit Delphi 6 Update Pack 2 tritt das Problem interessanterweise nicht auf (zumindest unter Win98).
Gruß Gammatester |
Re: [Variants] 0 = Unassigned, wieso das denn?
Moin Alzaimar,
Zitat:
|
Re: [Variants] 0 = Unassigned, wieso das denn?
Zitat:
|
Re: [Variants] 0 = Unassigned, wieso das denn?
Hallo alzaimar, ich verstehe dein Problem nicht wirklich. :gruebel:
Zitat:
Zitat:
Nach meinem Verständnis geht das mit Unassigned nicht. Unassigned ist lediglich dazu da, um eine Variant auf leer zu setzen, nicht um zu prüfen. Was würde man denn da auch prüfen? Leer = Leer? Nicht leer = Leer? Sein oder nicht sein? Auszug aus der MSDN: Eine Varianten-Variable kann leer sein, d.h., dass noch kein Wert zugewiesen wurde. Die Funktion Unassigned gibt eine leere Variante zurück, die einer Varianten-Variable zugewiesen werden kann, um den Anfangsstatus der Variable wiederherzustellen. Verwenden Sie die Funktion VarIsEmpty , um zu prüfen, ob eine Variante leer ist. Bei einer leeren Variante gibt die Standardfunktion VarType den Wert varEmpty zurück. Zur Verdeutlichung:
Delphi-Quellcode:
Sieh dir mal die Ergebnisse an. Soweit ich das verstehe ist leer != 0 und 0 != Null (und für den Fall der Fälle Null != nil)
procedure TForm1.FormCreate(Sender: TObject);
Var g: Variant; v: Variant; begin if g = v then ShowMessage('Leere Variant = Leere Variant ???'); if VarIsNull(v) then ShowMessage('VarIsNull vorher'); if VarIsEmpty(v) then ShowMessage('VarIsEmpty vorher'); v := 0; // Wert wird zugewiesen, Variant ist also nicht mehr leer, // könnte aber mit Unassigned wieder leer gesetzt werden. // if v = Unassigned then ShowMessage('Delphi ist (Del)phies'); if VarIsNull(v) then ShowMessage('VarIsNull mittendrin'); if VarIsEmpty(v) then ShowMessage('VarIsEmpty mittendrin'); v := Null; if VarIsNull(v) then ShowMessage('VarIsNull nachher'); if VarIsEmpty(v) then ShowMessage('VarIsEmpty nachher'); end; Ich hoffe, ich hab das nicht falsch verstanden. Guido. |
Re: [Variants] 0 = Unassigned, wieso das denn?
.
Hier noch schnell die Deklarationen nachgeschoben. Vielleicht hilfts! :-D
Delphi-Quellcode:
Guido.
function Unassigned: Variant;
begin _VarClear(TVarData(Result)); end; procedure _VarClear(var V: TVarData); begin // byrefs and those inline data types are easy if (V.VType and varDeepData) = 0 then V.VType := varEmpty else VarClearDeep(V); end; -------------------------------------------- function Null: Variant; begin _VarNull(TVarData(Result)); end; procedure _VarNull(var V: TVarData); begin _VarClear(V); V.VType := varNull; end; |
Re: [Variants] 0 = Unassigned, wieso das denn?
Zitat:
Delphi-Quellcode:
Wenn 'Unassigned' einen nicht zugewiesenen Variant bezeichnet, dann ist dieser Variant doch per definitionem nicht identisch mit einem zugewiesenen Variant (nämlich 0). Das ist aber hier der Fall. Der Vergleich der Variants wurde halt schlampig bzw. ungenau programmiert, so einfach ist das.
Var
vZero, vOne : Variant; Begin vZero := 0; vOne := 1; if vZero = Unassigned Then Showmessage('0 = Unassigned'); if vOne = Unassigned Then Showmessage('1 = Unassigned'); End; Zitat:
Nein, nicht leer, sondern 'nicht zugewiesen'. Laut Variant-Definition gibt es da einen Unterschied. In SQL initialisiere ich einen Wert mit NULL, bei Variants mit UnAssigned, denn NULL ist etwas anderes. Also, ich prüfe einmal auf 'jemals etwas zugewiesen' Eigentlich habe ich diesen Code;
Delphi-Quellcode:
Was ich erwarten würde:
If MyVariant = Null Then
Writeln('Die Variante ist NULL') Else if MyVariant = Unassigned Then Writeln('Der Variante wurde nie etwas zugewiesen') else Writeln('Die Variante hat einen nicht leeren Inhalt'); "Unassigned = X", wenn X=Unassigned und "Unassigned <> X" für alle anderen X. Das trifft aber nicht zu. Nach der von Dir zitierten OH (wo ich ruhig mal hätte nachschauen können), scheint ein Vergleich mit UnAssigned nicht zulässig. Das ist aber BS, denn wenn ich etwas zuweisen und ausgeben kann, muss ich auch darauf prüfen können. Wenn das nicht geht, stimmt etwas nicht. |
Re: [Variants] 0 = Unassigned, wieso das denn?
Zitat:
Zitat:
Entschuldige bitte folgenden flapsigen Vergleich, aber ich hoffe, er hilft.
Delphi-Quellcode:
Hinzu kommt, dass in Delphi boolsche Bedingungen mit 0 für false und alles andere für true gehandhabt wird. Das heißt, wenn deine if-Abfrage etwas anderes als 0 ergibt, wird es als true interpretiert.
if Äpfel1 = Äpfel2 then ... // gültiger Vergleich
if Äpfel1 = Essenfassen then ... // "ungüliger" Vergleich Und mal ehrlich, wenn man das mal so betrachtet:
Delphi-Quellcode:
Ich weiß, diese Vergleiche hinken! Aber bitte sieh es so, dass ich versuche, Licht in diese Zusammenhänge zu bringen. (Ich will nix Böses! :evil: )
if v = unassigned then
if "Variable mit irgendeinem Typ und irgendeinem Wert" = "Leere Variable, die irgendeinen Typ und irgendeinen Werte annehmen kann" then Zitat:
Zitat:
Zitat:
Delphi-Quellcode:
Was ist BS?
Nach der von Dir zitierten OH (wo ich ruhig mal hätte nachschauen können), scheint ein Vergleich mit UnAssigned nicht zulässig. Das ist aber BS, denn wenn ich etwas zuweisen und ausgeben kann, muss ich auch darauf prüfen können.
Sehen wir uns doch mal eine Variant-Variable an. Was ist das? Die MSDN schreibt da seitenweise Definitionen und wasweißichwasnoch dazu. Nur ein kurzer Ausschnitt: Eine Variante kann zur Laufzeit die verschiedensten Typen annehmen. Records, Mengen, statische Arrays, Dateien, Klassen, Klassenreferenzen und Zeiger sind jedoch standardmäßig nicht erlaubt. Varianten können also Werte beliebigen Typs mit Ausnahme von strukturierten Typen und Zeigern enthalten. Wenn Varianten Interfaces enthalten, kann über diese auf ihre Methoden und Eigenschaften zugegriffen werden. (Weitere Informationen finden Sie unter Objekt-Interfaces .) Varianten können auch dynamische Arrays und variante Arrays (ein spezieller Typ von statischen Arrays) aufnehmen (siehe "Variante Arrays"). Varianten können in Ausdrücken und Zuweisungen mit anderen Varianten, aber auch mit Integer-Werten, reellen Werten, Strings und Booleschen Werten kombiniert werden. Lassen wir das mal bei Seite. Ich versuche mich mal mit einer eigenen "gutbürgerlichen" Definition: Eine Variant Varibale kann viele verschiedene Werte und Datentypen annehmen. Wie will man nun zwei Variants mit einander vergleichen? Läuft ein solcher Vergleich nicht darauf hinaus, dass "Die Variable auf der linkgen Seite, die alle möglichen Datentypen und Werte annehmen kann" gleich "Der Variable auf der rechten Seite ist, die ebenfalls alle möglichen Datentypen und werte annehmen kann"? Das ist der alte "Äpfel mit Birnen vergleichen"-Vergleich. Probier mal das, vielleicht bringt das Licht in das Verständnis:
Delphi-Quellcode:
Es gibt einfach Dinge, die kann man nicht miteinander vergleichen!
procedure TForm1.Button1Click(Sender: TObject);
var p1: Pointer; // <- kein Variant, sondern Pointer ! p2: Pointer; // <- kein Variant, sondern Pointer ! s: string; begin // p1 und p2 sind uninitialisiert if p1 = p2 then ShowMessage('sind gleich') else ShowMessage('sind gleich'); p1 := nil; // auch wenn man diese Zeile weglässt, Ergebnis bleibt gleich if p1 = p2 then ShowMessage('sind gleich') else ShowMessage('sind gleich'); p2 := @s; // auch das hier kann man weglassen oder hinschreiben, der // nachfolgende Vergleich bringt immer das gleiche Ergebniss if p1 = p2 then ShowMessage('sind gleich') else ShowMessage('sind gleich'); end; Guido. Edit: Leicht formatiert. Edit2: Doch noch heftig formatiert. ;-) |
Re: [Variants] 0 = Unassigned, wieso das denn?
Zitat:
Gruß Gammatester |
Re: [Variants] 0 = Unassigned, wieso das denn?
Zitat:
@Gammatester: Danke für den Hinweis! Guido. |
Re: [Variants] 0 = Unassigned, wieso das denn?
Guido, ich weiss nicht, was Du mir beweisen oder erklären willst. Ich weiss sehr wohl, was Variants sind, wie sie definiert sind und wo der Unterschied zwischen einem 'unassigned' und einem 'null' Wert sind. Steht ja auch so im Sourcecode von Variants.pas.
Ich kann auch Variants vergleichen, die mit unterschiedlichen Datentypen gefüllt sind, sofern der stärkere Datentyp in den Schwächeren konvertiert werden kann. Soviel zu deinen Erklärungsversuchen, das man Äpfel nicht mit Essenfassen vergleichen kann. Kann man aber schon, wenn Äpfel und Essenfassen kompatible Variants. Es ist und bleibt ein Bug. Damit ist für mich die Sache erledigt, auch wenn in der OH steht, das man mit Unassigned nicht vergleichen kann. Es ist sogesehen kein Bug im herkömmlichen Sinne, aber wenn man Variants als polymorphen Datentyp mit einer derartiken Einschränkung der Allgemeingültigkeit implementiert, kann man seinen Code nicht deterministisch schreiben. Wenn ich auf Gleichheit prüfe, und gar nicht weiss, ob das ein Variant noch unassigned ist, dann ist das Ergebnis u.U. falsch, denn wenn v1=0 (oder '', 0.0 '31.12.1899' etc.) ist, ergibt ein Vergleich mit v2 auch dann TRUE, wenn der v2 noch nichts zugewiesen wurde. Und das ist definitiv falsch. (int)0 ist nun mal nicht identisch mit einem noch nicht zugewiesenen Wert. Unassigned ist sehr wohl ein eindeutiger Zustand eines Variants (varType = varEmpty, alle Felder = 0). Es wäre sehr wohl möglich, diesen Zustand mit anderen Zuständen zu vergleichen, aber der Code(Variants.pas) ignoriert den varType einfach und vergleicht nur die Werte der beiden Variants. Und das ist nunmal definitiv und 100% eindeutig unwiderlegbar beweisbar f.a.l.s.c.h. Zitat:
Zitat:
Zitat:
Zitat:
Zitat:
Über deinen Pointer-Vergleich decke ich den Mantel der Nächstenliebe (oder des Unverständnisses, denn ich weiss nicht, was Du mir klarmachen willst). |
Re: [Variants] 0 = Unassigned, wieso das denn?
Hallo alzaimar,
Zitat:
Zitat:
Zitat:
Zitat:
Guido. Edit-Bemerkung: Auch wenn ich ihn gerne gelöscht hätte, ich habe den Pointer-Vergleich drin gelassen. ... Als abschreckendes Beispiel! :mrgreen: |
Re: [Variants] 0 = Unassigned, wieso das denn?
Hi Guido, der Verdacht ist mir dann auch gekommen, das da ein kleines Misverständnis vorliegt. In der Tat wollte ich nur melden, das Delphi sich hier merkwürdig unorthogonal verhält. Da man aber nie fremden Code die Schuld geben soll, habe ich mich einfach hingestellt und gewartet, das mir Eier ins Gesicht fliegen. Sind aber nicht. Insofern scheint hier wirklich ein Bug bzw. eine Ungenauigkeit vorzuliegen.
Ich melde das mal an embarcadero/CodeGear/Borland/Inprise/Borland |
Re: [Variants] 0 = Unassigned, wieso das denn?
Alles klar! :thumb:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:41 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-2025 by Thomas Breitkreuz