Calocybe: Gleichheit von Referenzen (Objekten)

Moin Leuts!

Ich wuerde gerne feststellen, ob zwei Objektreferenzen dieselben sind. D.h. nicht, dass die Objekte denselben Inhalt haben, sondern das wirklich beide Referenzen auf ein und dieselbe Stelle zeigen. Ein Vergleichsoperator muss her. Nur welcher?
perlop sagt:
Binary "==" returns true if the left argument is numerically equal to the right argument.
Binary "eq" returns true if the left argument is stringwise equal to the right argument.

Passt vom Wortlaut her eigentlich beides nicht auf mein Problem. Ich will Referenzen vergleichen, keine Zahlen oder Strings. Aber probieren kann man's ja mal. Also ein kleines Testprogramm:

perl -w

$i = 3; $j = 3;
$x = $i; $y = $j; $z = $i;
print("x == y: ", $x == $y, "\n");
print("x eq y: ", $x eq $y, "\n");
print("x == z: ", $x == $z, "\n");
print("x eq z: ", $x eq $z, "\n");
^Z
x == y:
x eq y:
x == z: 1
x eq z: 1

Scheint also zu funktionieren (Perl 5.005_03 (ActiveState Build 522)). Nur ist es so nicht dokumentiert, d.h. das Funktionieren ist fuer andere Interpreter-Versionen nicht garantiert.

Gibt es also einen (anderen) offiziellen Weg? Oder ist das doch schon offiziell und ich hab die Dokumentation dazu bloss nicht gefunden?

Solange, Calocybe

  1. Hallo Calocybe

    perl -w
    $i = 3; $j = 3;
    $x = $i; $y = $j; $z = $i;
    print("x == y: ", $x == $y, "\n");
    print("x eq y: ", $x eq $y, "\n");
    print("x == z: ", $x == $z, "\n");
    print("x eq z: ", $x eq $z, "\n");
    ^Z
    x == y:
    x eq y:
    x == z: 1
    x eq z: 1

    Scheint also zu funktionieren (Perl 5.005_03 (ActiveState Build 522)). Nur ist es so nicht dokumentiert, d.h. das Funktionieren ist fuer andere Interpreter-Versionen nicht garantiert.

    Gibt es also einen (anderen) offiziellen Weg? Oder ist das doch schon offiziell und ich hab die Dokumentation dazu bloss nicht gefunden?

    Ich denke, das ist schon offiziell. Wo und ob das in der Dokumentation steht, weiss ich aber nicht.
    Im obigen Script wird ja einfach die Speicheradresse (z.B. SCALAR(0xba59b4)) der Referenzen verglichen. Das sollte auch in früheren Perl-Versionen funktionieren.
    Du kannst ja mal dieses Script ausführen:

    $i = 3; $j = 3;
    $x = $i; $y = $j; $z = $i;
    print('$x eq ', $x, "\n");
    print('$y eq ', $y, "\n");
    print('$z eq ', $z, "\n");

    Gruss
    Andreas

    1. Hallo Andreas!

      Im obigen Script wird ja einfach die Speicheradresse (z.B. SCALAR(0xba59b4)) der Referenzen verglichen.

      Aber woher *weisst* Du das?

      print('$x eq ', $x, "\n");
      print('$y eq ', $y, "\n");
      print('$z eq ', $z, "\n");

      Na gut, Du behandelst hier die Referenzen als String, woraufhin Sie in solche Dinge wie "SCALAR(0xca99c4)" konvertiert werden. Wenn dies bei den Vergleichen auch passieren wuerde, haette perl -w beim numerischen Vergleich aber eine Warnung ausgegeben, was jedoch nicht der Fall war. So ganz zufrieden bin ich damit also nicht.

      Bis dann, Calocybe

      1. Im obigen Script wird ja einfach die Speicheradresse (z.B. SCALAR(0xba59b4)) der Referenzen verglichen.
        Aber woher *weisst* Du das?

        Ich weiß es nicht, aber der Adreßoperator "" wird halt einen Datentyp produzieren, der vergleichbar ist (und bei seiner Definition müßte das eigentlich stehen). Ich würde ihn gefühlsmäßig sogar eher als Zahl behandeln (Hauptspeicheradresse).

        So ganz zufrieden bin ich damit also nicht.

        Sei froh, daß Du Dein Problem heute hast und nicht vor 10 Jahren!
        Damals gab es unter DOS noch 64-k-Segmente, und zwei Pointer zeigten selbst dann möglicherweise auf dasselbe Objekt, wenn Segmentnummer concat Offset zwischen beiden Adressen verschieden waren!
        Bei Motorola-CPUs war das nie ein Problem, bei Intels aber schon - ich denke, erst mit dem Pentium ist das repariert worden (wenn überhaupt, ich bin da nicht nah genug an der Hardware dran) ...

        1. Moin Michael!

          Ich weiß es nicht, aber der Adreßoperator "" wird halt einen Datentyp produzieren, der vergleichbar ist (und bei seiner Definition müßte das eigentlich stehen).

          Naja, der Datentyp heisst wohl Referenz und ist eine Art Skalar. Aber hab weder in perlref noch perlop noch perltoot noch perlobj was gefunden. Wo kann ich noch suchen?

          Ich würde ihn gefühlsmäßig sogar eher als Zahl behandeln (Hauptspeicheradresse).

          Naja, der Unterschied zwischen Pointer (z.B. Pascal, C, C++) und Referenz (z.B. C++, Java, JavaScript, Perl) ist halt, dass man beim Pointer weiss, dass es eine Adresse ist, das bei der Referenz aber per Definition nicht weiss (auch wenn naheliegend ist, dass es intern ja doch nur ein Pointer ist). Die Folge ist z.B. dass man mit Referenzen keine Pointer-Arithmetik veranstalten kann. Eine Referenz zeigt auf ein *Objekt* (bzw. Variable), nicht auf eine Adresse.

          Deshalb kann man vielleicht auch keine Referenzen vergleichen, weil das vom theoretischen Modell her wohl nicht so hinhaut. Aber sogesehen will ich das ja auch gar nicht; *eigentlich* will ich ja nur wissen, ob zwei Referenzen dasselbe Objekt bezeichnen. Vielleicht waere eine weitere Methode in der UNIVERSAL class namens 'is_same' oder so angebracht?

          Ich habe jetzt mal zum Spass nicht auf Gleichheit getestet, sondern auf groesser und kleiner als. Das Ergebnis ist genau das, als wuerde Perl Pointer vergleichen ($x ist kleiner als $y, denn $i wurde ja eher deklariert als $j).

          Damals gab es unter DOS noch 64-k-Segmente, und zwei Pointer zeigten selbst dann möglicherweise auf dasselbe Objekt, wenn Segmentnummer concat Offset zwischen beiden Adressen verschieden waren!

          long int address = (segment << 4) + offset;     /*  ;-)  */

          Die 64k Segmente gibt's auch heute noch bei Intel-kompatiblen Prozessoren. Im Real Mode (der nach dem Reset (==Anschalten) aktiv ist) musst Du Dich damit nach wie vor auseinandersetzen. Erst das Betriebssytem schaltet dann in Protected oder Virtual Mode um, wo Du die Probleme nicht mehr hast.

          Bei Motorola-CPUs war das nie ein Problem, bei Intels aber schon - ich denke, erst mit dem Pentium ist das repariert worden (wenn überhaupt, ich bin da nicht nah genug an der Hardware dran) ...

          Seit dem 80386 hat man im Protected Mode 32-Bit breite Offset-Adressen verwenden. Die Segmente gibt's zwar trotzdem noch, aber um die braucht man sich nicht mehr kuemmern, weil ein Segment 4 GB gross sein kann (eben 32 Bit). Hast Du noch groessere Anwendungen, naja, der Intel kann ja nur max. 4GB RAM auf der Platine adressieren, weil er nur 32 Leitungen dafuer hat. Virtuell kann er zwar mehr (46 TB?), dann muesstest Du ja aber staendig swappen. Daher ist spaetestens an der Stelle wohl eh' zu einer anderen Architektur zu raten.

          Naja, so lange erstmal