Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi [Variants] 0 = Unassigned, wieso das denn? (https://www.delphipraxis.net/116901-%5Bvariants%5D-0-%3D-unassigned-wieso-das-denn.html)

alzaimar 8. Jul 2008 13:13


[Variants] 0 = Unassigned, wieso das denn?
 
Hi,

ich arbeite mal wieder mit Variants und dabei kriege ich wegen folgendem Bug ne Krise:

Delphi-Quellcode:
Var
  v : Variant;

begin
  v := 0;
  if v = Unassigned then ShowMessage('Delphi ist (Del)phies');
end;
Was glaubt Ihr, zeigt mein Delphi? Genau! angeblich ist "0 = Unassigned". Kann mir mal einer den Müll erklären?

Klappt mit D6E und BDS2006, ich könnte :kotz:

Christian Seehase 8. Jul 2008 13:54

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.

iKilledKenny 8. Jul 2008 13:58

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;

alzaimar 8. Jul 2008 14:44

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).

iKilledKenny 8. Jul 2008 14:52

Re: [Variants] 0 = Unassigned, wieso das denn?
 
Der Workaround klappt sehr wohl.

VarIsEmpty == (v = Unassigned)
VarIsNull == (v = NULL)

gammatester 8. Jul 2008 15:02

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

Christian Seehase 8. Jul 2008 15:13

Re: [Variants] 0 = Unassigned, wieso das denn?
 
Moin Alzaimar,

Zitat:

Zitat von alzaimar
nur ist der Bug schon seit 317 Jahren im System.

vielleicht hat ihn ja bislang noch niemand gemeldet... ;-)

alzaimar 8. Jul 2008 17:48

Re: [Variants] 0 = Unassigned, wieso das denn?
 
Zitat:

Zitat von gammatester
Hatten wir nicht neulich schon mal was ähnliches? Mit Delphi 6 Update Pack 2 tritt das Problem interessanterweise nicht auf (zumindest unter Win98).

Äh, ich habe UP2 bei mir drauf, dachte ich zumindest ... Ach egal, der Workaround von iKilledKenny funktioniert.

Guido Eisenbeis 8. Jul 2008 19:33

Re: [Variants] 0 = Unassigned, wieso das denn?
 
Hallo alzaimar, ich verstehe dein Problem nicht wirklich. :gruebel:

Zitat:

Zitat von alzaimar
ich arbeite mal wieder mit Variants und dabei kriege ich wegen folgendem Bug ne Krise:

Wie kommst du darauf, dass das ein Bug ist?

Zitat:

Zitat von alzaimar
Hi,
Delphi-Quellcode:
Var
  v : Variant;

begin
  v := 0;
  if v = Unassigned then ShowMessage('Delphi ist (Del)phies');
end;

Was ist denn deine Absicht? Willst du prüfen, ob die Variant v leer ist (sprich kein Wert zugewiesen wurde)?

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:
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;
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)

Ich hoffe, ich hab das nicht falsch verstanden.

Guido.

Guido Eisenbeis 8. Jul 2008 19:40

Re: [Variants] 0 = Unassigned, wieso das denn?
 
.
Hier noch schnell die Deklarationen nachgeschoben. Vielleicht hilfts! :-D

Delphi-Quellcode:
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;
Guido.

alzaimar 8. Jul 2008 20:06

Re: [Variants] 0 = Unassigned, wieso das denn?
 
Zitat:

Zitat von Guido Eisenbeis
Hallo alzaimar, ich verstehe dein Problem nicht wirklich. :gruebel:

Ich bin davon ausgegangen, das ein Variant 'unassigned', 'Null' oder einen echten Wert haben kann. Ich kann diese Zustände jedenfalls setzen und ausgeben bzw. anzeigen. Wenn nun eine Variable einen Wert X annehmen kann, muss ich auch auf gleichheit prüfen können. Und wenn zwei Variablen unterschiedliche Werte haben, dann muss eine Prüfung auf Gleichheit misslingen. Das ist rein mathematisch notwendig, weil man sonst keine Ordnung und Eindeutigkeit hat.
Delphi-Quellcode:
Var
  vZero, vOne : Variant;

Begin
  vZero := 0; vOne := 1;
  if vZero = Unassigned Then Showmessage('0 = Unassigned');
  if vOne = Unassigned Then Showmessage('1 = Unassigned');
End;
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.

Zitat:

Zitat von Guido Eisenbeis
Was ist denn deine Absicht? Willst du prüfen, ob die Variant v leer ist (sprich kein Wert zugewiesen wurde)...Was würde man denn da auch prüfen? Leer = Leer? Nicht leer = Leer? Sein oder nicht sein??

Hö hö, Witsischkeit kennt keine Grentsen...
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:
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');
Was ich erwarten würde:
"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.

Guido Eisenbeis 8. Jul 2008 21:01

Re: [Variants] 0 = Unassigned, wieso das denn?
 
Zitat:

Zitat von alzaimar
Ich bin davon ausgegangen, das ein Variant 'unassigned', 'Null' oder einen echten Wert haben kann.

Hierbei ist ganz speziell beim Variant zu beachten, dass man außer dem Wert auch verschiedene Datentypen zuweisen kann, was eine Vergleich erschwert!

Zitat:

Zitat von alzaimar
Wenn 'Unassigned' einen nicht zugewiesenen Variant bezeichnet, ...

Hier liegt evtl. der Denkfehler. Sieh dir doch mal die Deklaration an. "Unassigned" bezeichnet nicht, sondern weist zu.

Entschuldige bitte folgenden flapsigen Vergleich, aber ich hoffe, er hilft.

Delphi-Quellcode:
if Äpfel1 = Äpfel2 then ... // gültiger Vergleich
if Äpfel1 = Essenfassen then ... // "ungüliger" Vergleich
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.

Und mal ehrlich, wenn man das mal so betrachtet:

Delphi-Quellcode:
if v = unassigned then
if "Variable mit irgendeinem Typ und irgendeinem Wert" = "Leere Variable, die irgendeinen Typ und irgendeinen Werte annehmen kann" then
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: )

Zitat:

Nein, nicht leer, sondern 'nicht zugewiesen'. Laut Variant-Definition gibt es da einen Unterschied.
Da hattu recht! :wink:

Zitat:

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'
Das sehe ich genauso. Zusätzlich kann man mit Unassigned eine Variant auch wieder jungfräulich machen. Als wäre nie was gewesen. Würde das nur in anderen Bereichen funktionieren! :mrgreen:


Zitat:

Eigentlich habe ich diesen Code;
Delphi-Quellcode:
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');
Was ich erwarten würde:
"Unassigned = X", wenn X=Unassigned und "Unassigned <> X" für alle anderen X. Das trifft aber nicht zu.
Äh, ... häh? :gruebel:

Delphi-Quellcode:
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.
Was ist BS?

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:
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;
Es gibt einfach Dinge, die kann man nicht miteinander vergleichen!

Guido.

Edit: Leicht formatiert.
Edit2: Doch noch heftig formatiert. ;-)

gammatester 8. Jul 2008 21:41

Re: [Variants] 0 = Unassigned, wieso das denn?
 
Zitat:

Zitat von Guido Eisenbeis
Delphi-Quellcode:
  if p1 = p2 then
    ShowMessage('sind gleich')
  else
    ShowMessage('sind gleich');
end;
Es gibt einfach Dinge, die kann man nicht miteinander vergleichen!

Aber offensichtlich kommt trotzdem raus, das sie immer gleich sind:) Sorry, aber diese kleinen Tippfehler waren zu verlockend. Hättest halt ruhig ein 9tes Mal eidtieren sollen :)

Gruß Gammatester

Guido Eisenbeis 8. Jul 2008 23:00

Re: [Variants] 0 = Unassigned, wieso das denn?
 
Zitat:

Zitat von gammatester
Zitat:

Zitat von Guido Eisenbeis
Delphi-Quellcode:
  if p1 = p2 then
    ShowMessage('sind gleich')
  else
    ShowMessage('sind gleich'); // hier sollte eigentlich "sind NICHT gleich" stehen :-(
end;
Es gibt einfach Dinge, die kann man nicht miteinander vergleichen!

Aber offensichtlich kommt trotzdem raus, das sie immer gleich sind:) Sorry, aber diese kleinen Tippfehler waren zu verlockend. Hättest halt ruhig ein 9tes Mal eidtieren sollen :)

Gruß Gammatester

Verdammt, das ist natürlich übel. Vergesst diesen letzten Vergleich. Für heute geb ichs auf und geh ins Bett!

@Gammatester: Danke für den Hinweis!

Guido.

alzaimar 9. Jul 2008 06:35

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 von Guido Eisenbeis
Hier liegt evtl. der Denkfehler. Sieh dir doch mal die Deklaration an. "Unassigned" bezeichnet nicht, sondern weist zu.

Nein. Weise einer Variable 'Unassigned' zu und gehe im Debugger mit dem Cursor rauf. Was siehst Du? Im englischen Delphi sehe ich 'Unassigned' :shock:
Zitat:

Zitat von Guido Eisenbeis
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.

Hat doch gar nichts mit meinem Problem zu tun.

Zitat:

Was ist BS?
BullShit.
Zitat:

Die MSDN schreibt da seitenweise Definitionen ...
Ich programmiere in Delphi, nicht in MSDN. :stupid:
Zitat:

Wie will man nun zwei Variants mit einander vergleichen?
Steht in Variants.Pas.

Über deinen Pointer-Vergleich decke ich den Mantel der Nächstenliebe (oder des Unverständnisses, denn ich weiss nicht, was Du mir klarmachen willst).

Guido Eisenbeis 9. Jul 2008 14:55

Re: [Variants] 0 = Unassigned, wieso das denn?
 
Hallo alzaimar,

Zitat:

Zitat von alzaimar
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.

Aus eben diesem Grund habe ich anfangs gefragt, was deine Absicht, also deine eigentliche Frage ist. Mittlerweile habe ich festgestellt, dass ich wohl heftig am Ziel vorbeigeschossen bin, Klarheit in die Sache zu bringen. Das deutet darauf hin, dass auch die Klarheit in deiner Fragestellung fehlt. Da du ja schon alles weißt, was ich zur Klärung beitragen wollte, habe ich den Eindruck, dass du keine wirkliche Frage stellen, sondern eher deinem Frust über die Erkenntnis der scheinbaren Unstimmigkeiten in Delphi Luft machen wolltest.

Zitat:

Zitat von alzaimar
Ich bin davon ausgegangen, das ein Variant 'unassigned', 'Null' oder einen echten Wert haben kann. ... Das ist rein mathematisch notwendig, weil man sonst keine Ordnung und Eindeutigkeit hat.

Dies deutet auf ein "Frustablassen" hin. Wenn dem so ist, kann ich das verstehen. :?

Zitat:

Zitat von alzaimar
Es ist und bleibt ein Bug. Damit ist für mich die Sache erledigt, ...

Scheinbar initialisiert Delphi Variants von Anfang an (mit dem Wert 0). Das würde "Unassigned" wiedersprechen. Das macht Delphi aber auch z. B. mit Boolean. Ob man das als Bug sehen will, sei dahingestellt. Im Falle von "Unassigned" würde ich es tatsächlich als nicht korrekt ansehen. (Dafür aber als bequem! :mrgreen: )

Zitat:

Zitat von alzaimar
Über deinen Pointer-Vergleich decke ich den Mantel der Nächstenliebe ...

Vielen Dank! :oops: "Ich war jung, und ich brauchte das Geld!" :roll: Das war offensichtlich ein Schuss in den Ofen. Es war echt schon spät, und Guido sehr, sehr müde ...

Guido.


Edit-Bemerkung: Auch wenn ich ihn gerne gelöscht hätte, ich habe den Pointer-Vergleich drin gelassen. ... Als abschreckendes Beispiel! :mrgreen:

alzaimar 9. Jul 2008 15:24

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

Guido Eisenbeis 9. Jul 2008 21:48

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