Jeena Paradies: Vergleich zweier gleicher Arrays gibt false zurück

Hallo,

warum gibt in JavaScript [1] == [1] false aber 1 == 1 true aus?

Jeena

  1. Hello,

    warum gibt in JavaScript [1] == [1] false aber 1 == 1 true aus?

    ich rate: Arrays werden in JavaScript, ähnlich wie in Java, per Default nicht über den Inhalt sondern die Referenz verglichen.

    MfG
    Rouven

    --
    -------------------
    sh:| fo:} ch:? rl:( br:& n4:{ ie:| mo:} va:) js:| de:] zu:| fl:( ss:) ls:& (SelfCode)
    Because good guys need a break every once in a while.  --  Morty in "Click" (Columbia Pictures, 2006)
  2. Hallo Jeena,

    warum gibt in JavaScript [1] == [1] false aber 1 == 1 true aus?

    == vergleicht bei Objekten (Arrays sind in JS Objekte) nur, ob die Variablen eine Referenz auf's gleiche Objekt sind, nicht jedoch auf Gleichheit des Objektinhalts.

    Siehe z.B.: http://forum.de.selfhtml.org/archiv/2006/11/t140356/

    Viele Grüße,
    Christian

    1. Hallo,

      == vergleicht bei Objekten (Arrays sind in JS Objekte) nur, ob die Variablen eine Referenz auf's gleiche Objekt sind, nicht jedoch auf Gleichheit des Objektinhalts.

      Genau. Und zwar gilt das für alle Objekte im Gegensatz zu sogenannten primitive values. Kein Objekt ist mit einem anderen gleich, es sei denn, es ist mit ihm identisch. Gleich sind nur Primitives (daher 1 == 1), Objektes haben keine Gleichheit, sondern nur Identität (eine »Hausnummer«, das Verweisen auf eine bestimmte Speicherstelle, wie du sagst).

      Da habe ich schon öfters etwas zu geschrieben:
      </archiv/2006/12/t141628/#m920393>
      </archiv/2005/9/t114730/#m732136>
      </archiv/2007/4/t151203/#m983410>

      Mathias

    2. Hallo,

      == vergleicht bei Objekten (Arrays sind in JS Objekte) nur, ob die Variablen eine Referenz auf's gleiche Objekt sind, nicht jedoch auf Gleichheit des Objektinhalts.

      Ok, danke für die Erklärung. Irgendwie kann ich das aber nicht so richtig gut finden. Wenn man so einen Vergleich macht dann will man doch eigentlich fast immer dass da true rauskommt.

      Jeena

      1. Hallo Jeena!

        Wenn man so einen Vergleich macht dann will man doch eigentlich fast immer dass da true rauskommt.

        Mit meinem frührern »Verständnis« der Programmierung hätte ich genauso reagiert wie Du. Heute bin ich 2cm weiter, und es erscheint mich logisch (hier mit Perl):

        my $a = [1];  
        my $b = [1];  
        my $x = 1;  
        my $y = 1;  
          
        # $/ entspricht defaultmässig \n, wenn nicht anders definiert...  
          
        print '$a: ', $a, $/;  
        print '$b: ', $b, $/;  
        print '$x: ', $x, $/;  
        print '$y: ', $y, $/;  
          
        print 'VERGLEICH $a <-> $b:', $/;  
        if ($a == $b) { print "TRUE\n"; } else { print "FALSE\n"; }  
        print 'VERGLEICH $x <-> $y:', $/;  
        if ($x == $y) { print "TRUE\n"; } else { print "FALSE\n"; }
        

        Ausgabe:
        $a: ARRAY(0x35218) <- Na?
        $b: ARRAY(0x35434) <- Klingelt's?
        $x: 1
        $y: 1
        VERGLEICH $a <-> $b:
        FALSE
        VERGLEICH $x <-> $y:
        TRUE

        Viele Grüße aus Frankfurt/Main,
        Patrick

        --

        _ - jenseits vom delirium - _
        [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
        Nichts ist unmöglich? Doch!
        Heute schon gegökt?
        1. Hallo,

          $a: ARRAY(0x35218) <- Na?
          $b: ARRAY(0x35434) <- Klingelt's?

          Mir ist schon klar dass das nicht das selbe Array ist, aber es die beiden sind doch gleich.

          $a = [1]
          $b = [1]
          If $a Equals $b
          Then TRUE
          Else FALSE
          => TRUE

          $a = [1]
          $b = $a // Referenz nicht Kopie
          If $a is $b
          Then TRUE
          Else FALSE
          => TRUE

          $a = [1]
          $b = $a.clone() // Kopie
          If $a is $b
          Then TRUE
          Else FALSE
          => FALSE

          So weit ich des Englischen mächtig bin heißt = "equals"

          Jeena

          1. So weit ich des Englischen mächtig bin heißt = "equals"

            eben, du brauchst eine equals Funktion. leider hast du nicht gesagt was für eine Sprache das ist (für mich sieht's nach VB aus), aber offensichtlich gibt es dort eine equals Funktion für Arrays, die die Elemente vergleicht. In JS (und vielen anderen Sprachen) musst du dir diese selbst bauen (s. mein anderes Posting)

            Struppi.

            1. Hallo,

              So weit ich des Englischen mächtig bin heißt = "equals"

              eben, du brauchst eine equals Funktion. leider hast du nicht gesagt was für eine Sprache das ist (für mich sieht's nach VB aus), aber offensichtlich gibt es dort eine equals Funktion für Arrays, die die Elemente vergleicht. In JS (und vielen anderen Sprachen) musst du dir diese selbst bauen (s. mein anderes Posting)

              Oh hehe, ich glaube da haben wir uns missverstanden eigentlich wollte ich schreiben:

              'So weit ich des Englischen mächtig bin heißt das Zeichen "=" "equals" in Englisch.'

              Das war nur pseudocode und eigentlich wollte ich damit den unterschied zwischen "is" und "equals" verdeutlichen. Ich verstehe auch dass es so in JavaScript (im gegenteil zu Java, wo wie du schreibst "==" da true ausgibt) ist, ich wundere mich nur warum man sich dafür entschieden hat das so zu spezifizieren, da ich der meinung bin dass man ja meistens will dass da true herauskommt und für die wenigen ausnahmen, da wäre es dann sinnvoller eine .is() Methode zu haben, wie das wohl bei Java (auf jeden fall aber z.B. in Ruby) ist.

              Jeena

              1. Hallo,

                ich wundere mich nur warum man sich dafür entschieden hat das so zu spezifizieren

                Weil es eine ganz allgemeine Regel ist, die alle Objects betrifft.

                Es besteht kein Problem, wenn ein Arrays nur Primitives enthält. Das heißt, [1, 2, 3] == [1, 2, 3] ist natürlich trivial zu vergleichen.

                Wenn das nicht der Fall ist, läuft der Wunsch, zwei Arrays zu vergleichen, auf einen allgemeinen Algorithmus hinaus, der die Gleichheit von Objekten prüft. Zum Beispiel beim Vergleich [window] == [window], der auf window == window hinausläuft, wäre ein definiertes Konzept von Gleichheit nötig, wenn == nicht bloß die Identität der Objekte prüfen soll.

                Sinnvollerweise und unsinnigerweise sähe dieses Konzept so aus, dass der Interpreter alle Member durchgeht und vergleicht. Wenn es sich um Objekte handelt, müsste er wieder dessen Member vergleichen, rekursiv halt. Das wäre bei window == window reiner Overkill.

                Will man das vermeiden, müsste man jedem Objekttyp seine eigene equals-Methode geben, die den Operator == überlädt. Die könnte dann einfacher und spezifischer sein. Dann hat man aber keine allgemeine Operanden-unabhängige Bedeutung von ==, man könnte die Resultate nicht mit ein paar Regeln abschätzen.

                Mathias

          2. Hallo Jeena!

            nicht das selbe Array ist, aber es die beiden sind doch gleich.

            Sie enthalten Elemente mit dem gleichen Wert, ja. Aber in Vorahnung einer ähnlichen Frage hatte ich gestern abend das gepostete Beispiel fortgeführt ;)

            my $a = [1];  
            my $b = [1];  
            my $x = 1;  
            my $y = 1;  
              
            # $/ entspricht defaultmässig \n, wenn nicht anders definiert...  
              
            print '$a: ', $a, $/;  
            print '$b: ', $b, $/;  
            print '$x: ', $x, $/;  
            print '$y: ', $y, $/;  
              
            print 'VERGLEICH $a <-> $b:', $/;  
            if ($a == $b) { print "TRUE\n"; } else { print "FALSE\n"; }  
            print 'VERGLEICH $x <-> $y:', $/;  
            if ($x == $y) { print "TRUE\n"; } else { print "FALSE\n"; }  
            print 'Jetzt dereferenzieren wir... und vergleichen somit den _Inhalt_:', $/;  
            if ($a->[0] == $b->[0]) { print "TRUE\n"; } else { print "FALSE\n"; }  
            print 'Jetzt stiften wir Verwirrung...:', $/;  
            print \$x, $/;  
            print \$y, $/;  
            print 'OBJEKT-VERGLEICH FUER SKALARE $x <-> $y: ', $/;  
            if (\$x == \$y) { print "TRUE\n"; } else { print "FALSE\n"; }
            

            Ausgabe:
            $a: ARRAY(0x35200)
            $b: ARRAY(0x3541c)
            $x: 1
            $y: 1
            VERGLEICH $a <-> $b:
            FALSE
            VERGLEICH $x <-> $y:
            TRUE
            Jetzt dereferenzieren wir... und vergleichen somit den _Inhalt_:
            TRUE
            Jetzt stiften wir Verwirrung...:
            SCALAR(0x18311a0)
            SCALAR(0x18311c4)
            OBJEKT-VERGLEICH FUER SKALARE $x <-> $y:
            FALSE

            Viele Grüße aus Frankfurt/Main,
            Patrick

            --

            _ - jenseits vom delirium - _
            [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
            Nichts ist unmöglich? Doch!
            Heute schon gegökt?
        2. Mit meinem frührern »Verständnis« der Programmierung hätte ich genauso reagiert wie Du. Heute bin ich 2cm weiter, und es erscheint mich logisch (hier mit Perl):

          Und wer nochmal 2cm weiter ist, dem erscheint das hier logisch (hier mit Python):
          * [1, 2, 3] == [1, 2, 3]
          True

          Und nun?

          1. Hallo,

            Und nun?

            Andere Sprachen, andere Konventionen. In PHP hast Du das gleiche Verhalten, wie in Python. Und in Perl auch, wenn Du nicht mit Referenzen auf Listen, sondern mit Listen selbst arbeitest (siehe Patricks anderes Posting). So what?

            Viele Grüße,
            Christian

          2. Hallo,

            * [1, 2, 3] == [1, 2, 3]

            Was würde Python bei einem Vergleich zweier komplexerer Objekte machen, also wie in JavaScript das besagte window == window?

            Mathias

            1. Hallo Mathias,

              * [1, 2, 3] == [1, 2, 3]

              Was würde Python bei einem Vergleich zweier komplexerer Objekte machen, also wie in JavaScript das besagte window == window?

              Kommt darauf an[tm].

              Wenn die Klasse spezielle Methoden (__eq__, __cmp__) implementiert, dann werden diese Methoden aufgerufen, um Vergleiche durchzuführen. Wenn nicht, dann wird nur geprüft, ob die Variablen Referenzen auf das gleiche Objekt sind.

              Beispiel:

              Klasse mit Vergleichsfunktion:

              class Bar:  
                def __init__ (self, a):  
                  self.a = a  
                
                def __eq__ (self, other):  
                  return self.a == other.a
              

              Klasse ohne Vergleichsfunktion:

              class Foo:  
                def __init__ (self, a):  
                  self.a = a
              

              Ausgabe (Beispiel):

              t1 = Foo (1)
              t2 = t1
              t3 = Foo (1)
              t1 == t2

              True

              t1 == t3

              False

              s1 = Bar(1)
              s2 = s1
              s3 = Bar(1)
              s1 == s2

              True

              s1 == s3

              True

              Viele Grüße,
              Christian

          3. Hi Christian

            Und wer nochmal 2cm weiter ist, dem erscheint das hier logisch (hier mit Python):
            * [1, 2, 3] == [1, 2, 3]
            True

            Und nun?

            und nun sagst du mir  wie Python die identität zweier listenvariablen überprüfe?
            sprich in Perl
            \@a == \@b

            (habs jetzt in der Guido-dokiu nicht gefunden...)

            Grüße
             LanX

            1. Hi Christian

              vielleicht beser  "Hi Timo" :)

            2. Hallo!

              und nun sagst du mir  wie Python die identität zweier listenvariablen überprüfe?
              sprich in Perl
              \@a == \@b

              [1,2,3] is [1,2,3]

              (ergibt: False)

              Viele Grüße,
              Christian

      2. == vergleicht bei Objekten (Arrays sind in JS Objekte) nur, ob die Variablen eine Referenz auf's gleiche Objekt sind, nicht jedoch auf Gleichheit des Objektinhalts.
        Ok, danke für die Erklärung. Irgendwie kann ich das aber nicht so richtig gut finden. Wenn man so einen Vergleich macht dann will man doch eigentlich fast immer dass da true rauskommt.

        Tut es ja auch, wenn es die gleichen Objekte sind.
        Wenn du wissen willst ob bestimmte Eigenschaften (z.b. der Array inhalt) gleich sind, wird z.b. in Java der Gleichheitsoperator überladen mit eine equals() Funktion, in Javascript leider nicht.

        In deinem Fall müßte es so aussehen:

        Array.prototype.equals = function(p) {  
         if(this.length != p.length) return false;  
         for(var i = 0; i < this.length; i ++) if( this[i] != p[i]) return false;  
         return true;  
        }  
        alert( [1].equals([1]));
        

        Struppi.

        1. HI

          In deinem Fall müßte es so aussehen:

          Array.prototype.equals = function(p) {

          if(this.length != p.length) return false;
          for(var i = 0; i < this.length; i ++) if( this[i] != p[i]) return false;
          return true;
          }
          alert( [1].equals([1]));

            
          Überlädt equals jetzt den == operator, oder definierst du hier ne neue Methode equals? Konnte dazu jetzt nichts googlen.  
            
          Davon ist nämlich abhängig ob Unterarrays dann mit this[i] != p[i] auch rekursiv untersucht werden, ansonsten müsste es sowas wie  
          ! this[i].equals(p[i])  
          heißen.  
            
          Anders: Ohne overloading würde deine methode in Perl nur ein @this=@p realisieren.  
            
          Außerdem würde ich als erstes noch den Fall abfangen, das beide verglichenen Arrays identische Objekte sind und dafür sofort true zurückliefern. Spart rekursionen.  
            
          Desweiteren müsste noch diskutiert werden inwieweit sich Ringstrukturen auswirken, da müsste eine Rekursion rechtzeitig abgebrochen werden sonst gibts ne böse Endlosschleife,z.B.  
          [code lang=javascript]  
          a=b=Array();  
          a=[b,...];  
          b=[a,...];  
          [code lang=javascript]  
            
          Bye  
           KurtZ
          
          1. Nachtrag:

            Desweiteren müsste noch diskutiert werden inwieweit sich Ringstrukturen auswirken, da müsste eine Rekursion rechtzeitig abgebrochen werden sonst gibts ne böse Endlosschleife,z.B.

            a=b=Array();
            a=[b,...];
            b=[a,...];

              
            was jetzt auch erklären dürfte warum man bei nicht primitiven Datenstrukturen die Ringstrukturen erlauben erstmal nur auf den Vergleich der Referenzen abhebt.  
              
              
            Die Frage ist wie das hier so gelobte Python mit Ringstrukturen umgeht.  
              
            also sowas wie  
            ~~~python
              
            b=[]  
            a=[b,1]  
            b=[a,2]  
              
            d=[]  
            c=[d,1]  
            d=[c,2]  
              
            a==c  
            
            

            ahh super Pustekuchen, ich kann gar keine Ringstruktur bauen ...

              
            
            >>> a  
            
            [[], 1]  
            
            

            Na wen das nicht besser geht, dann kann ich doch gleich bei Perllisten bleiben.

          2. Hallo,

            Überlädt equals jetzt den == operator, oder definierst du hier ne neue Methode equals?

            Letzteres natürlich. Es gibt kein Operatoren-Overloading in ECMAScript Edition 3.

            Davon ist nämlich abhängig ob Unterarrays dann mit this[i] != p[i] auch rekursiv untersucht werden

            Werden sie nicht.

            Das ist die Aussage dieses Thread: Man kann Arrays einfach vergleichen, solange sie nur Primitives enthalten. Das war es aber auch.

            ansonsten müsste es sowas wie
            ! this[i].equals(p[i])
            heißen.

            Okay, prinzipiell kann man auch Arrays rekursiv miteinander vergleichen, solange die Arrays nur Primitives bzw. weitere Arrays bestehend aus Primitives enthalten. Dazu macht man this[i].equals(p[i]), wenn beide Operanden Arrays sind, ansonsten halt this[i] != p[i]. Das muss man aber manuell prüfen, da gibts kein Overloading.

            Mathias

            1. Hi

              Okay, prinzipiell kann man auch Arrays rekursiv miteinander vergleichen, solange die Arrays nur Primitives bzw. weitere Arrays bestehend aus Primitives

              enthalten.

              Dazu macht man this[i].equals(p[i]), wenn beide Operanden Arrays sind, ansonsten halt this[i] != p[i]. Das muss man aber manuell prüfen, da gibts kein Overloading.

              M.E. geht das eben nicht wirklich, weil man mit Referenzen Ringstrukturen bauen kann, d.h. die Rekursion würde nie abbrechen. Eine allgemeingültige rekursive Realisierung als Methode des Objects Array halte ich nur für sehr schwierig zu realisieren.

              Sprachen die eine rekursive Überprüfung erlauben, wie z.B. Python erlauben scheinbar auch nicht Referenzen in Arrays einzutragen (Verschachtelungen erfolgen AFAIS bei Value) und machen so Rückbezüglichkeiten unmöglich.

              M.a.W. man kann vernünftigerweise == nicht anders in JS definieren, weil die Arrays mehr erlauben als in Python.(wie es in Java realisiert ist wäre auch interessant zu erfahren)

              Und wäre overloading von == in JS erlaubt, hätte man schnell eine rekursive Endlosschleife gebaut...

              Sowas wie einen rekursiven Vergleich kann ich mir deswegen nur als komplexe Methode vorstellen, die sich Rückbezüge merkt und den Suchbaum dort abschneidet. Am besten als Klassenmethode Array.compare(arr1,arr2)

              Gruß
               Kurt

              1. Hi

                Sprachen die eine rekursive Überprüfung erlauben, wie z.B. Python erlauben scheinbar auch nicht Referenzen in Arrays einzutragen (Verschachtelungen erfolgen AFAIS bei Value) und machen so Rückbezüglichkeiten unmöglich.

                Bin mittlerweile schlauer, diese Sorte Arrays in Python müssen mit "Tupeln" [] und nicht mit "Listen" () realisiert werden, um Rückbezüge zu ermöglichen:

                  
                
                >>> A=['A']  
                >>> B=['B',A]  
                >>> A.append(B)  
                >>> a=['A']  
                >>> b=['B',a]  
                >>> a.append(b)  
                >>> A  
                
                ['A', ['B', [...]]]  
                
                >>> a  
                
                ['A', ['B', [...]]]  
                
                >>> B  
                
                ['B', ['A', [...]]]  
                
                

                Der rekursive Vergleich klappt dann tatsächlich auch!

                  
                
                >>> A == a  
                
                True  
                
                

                Das ist scheints mir sehr gut umgesetzt!!!

                Grüße
                 Kurt

                1. Hallo Kurt,

                  Bin mittlerweile schlauer, diese Sorte Arrays in Python müssen mit "Tupeln" [] und nicht mit "Listen" () realisiert werden, um Rückbezüge zu ermöglichen:

                  Du hast da was falsch verstanden: Tupel konstruiert man mit normalen Klammern - (1, 2) - Listen mit eckigen Klammern - [1, 2, 3] - anders als von Dir gesagt. Du nutzt also Listen.

                  Wo ist der Unterschied? Listen sind nun mal Listen, lang und veränderbar. Tupel dagegen sind fix, man kann sie nicht verändern. Idealerweise stellst Du Dir Tupel nicht als „nicht veränderbare Listen“ vor, sondern gehst mehr der mathematischen Sichtweise aus: Tupel sind dort aufzählbare Strukturen von Objekten, die aus Einzeldaten bestehen. Denk zum Beispiel an Positionen in einem zweidimensionalen Koordinatensystem (X- und Y-Wert) oder allgemeiner an Vektoren. Oder eben an alle möglichen Datensätze, ein Geburtsdatum wäre z.B. als ein Tupel aus Jahr, Monat und Tag (die Einzelwerte sind alles Zahlen) interpretierbar.

                  D.h. Tupel sind eher ein struktureller Datentyp für all die Fälle, für die man nicht unbedingt ein extra Objekt mit extra Klasse und Methoden und allem Pipapo erschaffen will, um das rumzureichen, sondern für all die kleinen Fälle. Und weil das so praktisch ist, ist das recht gut in die Sprache integriert. Links von der Zuweisung kann man z.B. Tuple Unpacking betreiben:

                  ~~~python-shell

                  position = (5, 3)

                  >>> position
                    (5, 3)
                    >>> x, y = position
                    >>> x
                    5
                    >>> y
                    3

                    
                  D.h. eigentlich wird das Tupel syntaktisch durch die Kommata bestimmt, nur zur syntaktischen Klarheit werden die Klammern drum gemacht:  
                    
                    ~~~python-shell
                  
                  >>> x, y  
                  
                    (5, 3)
                  

                  Genau das ist auch der Grund, weswegen das Rückgeben mehrerer Einzel-Werte aus Funktionen klappt. Die Funktion divmod() aus den Builtins von Python ist ja so definiert:

                  ~~~python def divmod(x, y):
                    return x // y, x % y

                    
                  Effektiv wird da ein Tupel zurückgegeben; das Paar aus Divisor und Rest:  
                    
                    ~~~python-shell
                  
                  >>> divisor, remainder = divmod(11, 3)  
                  
                    >>> print divisor, "Rest:", remainder  
                    3 Rest: 2  
                    >>> t = divmod(11, 3)  
                    >>> type(t)  
                    <type 'tuple'>  
                    >>> print t  
                    (3, 2)
                  

                  Tupel haben noch andere Vorteile – die Unveränderbarkeit hat z.B. den praktischen Effekt, dass man sie als Key in einem Dictionary nehmen kann – aber in der Suche auf Deine Ringstrukturen bist Du da auf dem Holzweg.

                  ...

                  Denn die sind wunderbar mit Listen möglich, wie Du es ja auch vorgeführt hast. Nur hier hast Du einen Fehler begangen, der Dich da auf den Weg brachte, es sei nicht möglich.

                  ~~~python-shell

                  A = [1, 2]

                  >>> B = [0, A]
                    >>> B
                    [0, [1, 2]]

                    
                  Anhand der ID – ganz einfach der Speicheradresse - kann man überprüfen, dass die Variable A und das zweite Element von B wirklich auf das gleiche Objekt zeigen; es referieren:  
                    
                    ~~~python-shell
                  
                  >>> id(A)  
                  
                    420800  
                    >>> id(B[1])  
                    420800B  
                    >>> A is B[1]  
                    True  
                    >>> A in B  
                    True
                  

                  Und jetzt kommt das, was Du in Deinem Posting von Donnerstag falsch gemacht hast:

                  >>> A = [4, 5]

                  Du änderst das Objekt, auf das A zeigt hier nämlich NICHT. Du erstellst ein NEUES Listen-Objekt – und das ist logischerweise ein anderes. Das vorherige Objekt wurde aber noch nicht von der Garbage Collection gefressen; schließlich existiert eine Referenz an zweiter Stelle in der Liste B darauf:

                  ~~~python-shell

                  id(A)

                  419120
                    >>> id(B[1])
                    420800
                    >>> A is B[1]
                    False

                    
                  Also schnell wieder rückgängig machen und A wieder die passende Referenz auf das richtige Objekt verpassen:  
                    
                    ~~~python-shell
                  
                  >>> A = B[1]  
                  
                    >>> id(A)  
                    420800
                  

                  Die Ringstruktur kriegst Du hin, indem Du logischerweise das von A referenzierte Objekt selber änderst; mit den zugehörigen Methoden und Zuweisungen:

                  ~~~python-shell

                  A[1] = B

                  >>> id(A)
                    420800
                    >>> id(B)
                    420760
                    >>> id(A[1])
                    420760
                    >>> id(B[1])
                    420800

                    
                  Also nix weiter als ein kleiner Verständnisfehler.  
                    
                    
                  Tim
                  
                  1. Hi Tim

                    Du hast da was falsch verstanden: Tupel konstruiert man mit normalen Klammern - (1, 2) - Listen mit eckigen Klammern - [1, 2, 3] - anders als von Dir gesagt. Du nutzt also Listen.

                    ja danke ...  der Dreher ist mir auch aufgefallen, ich nutze halt vorwiegend Perl und da entsprechen Python-Listen eher Perl-Arrays und Python-Tupel eher Perl-Listen (die es nur Literal gibt ansonsten werden sie in Arrays konvertiert).

                    Aber ich wollte jetzt nicht die dritte Antwort auf mich selbst posten, zu monologisch ... :)

                    Denn die sind wunderbar mit Listen möglich, wie Du es ja auch vorgeführt hast. Nur hier hast Du einen Fehler begangen, der Dich da auf den Weg brachte, es sei nicht möglich.

                    ja den gleichen Fehler hab ich auch im Javascript Beispiel gemacht, interessanterweise ist der Syntax in allen drei Sprachen gleich nur die Terminonolgie ändert sich

                    z.B.
                     =[0,1,[20,21]]
                    gibt mir die Referenz auf ein 3 elemntiges Array mit einem 2 elementigen Subarray am Ende.

                    Summa summarum muss man anmerken das man in allen Sprachen zwischen dem "selben" und dem "gleichen" Objekt/Datentyp unterscheiden muss und dafür einen jeweils eigenen Syntax braucht. (in Python mit den Operatoren "==" und "is" )

                    Ciao
                     Kurt

                    1. Hallo Kurt,

                      ja danke ...  der Dreher ist mir auch aufgefallen, ich nutze halt vorwiegend Perl und da entsprechen Python-Listen eher Perl-Arrays und Python-Tupel eher Perl-Listen (die es nur Literal gibt ansonsten werden sie in Arrays konvertiert).

                      Mein Perl ist brüchig bis kaum vorhanden, aber wenn Du mit Perl-Listen die Syntax ($a, $b, $c) meinst und Perl-Arrays die Syntax [$a, $b, $c], dann .. sind pythonische Tupel immer noch nicht wirklich Listen im Sinne von Perl, so dass Interpolation statt findet. Im Tupel ist dann immer noch eine Referenz gespeichert:

                      >>> s = 1
                        >>> t = (s, 2)
                        >>> id(s)
                        16790920
                        >>> id(t)
                        420640
                        >>> id(t[0])
                        16790920

                      Variablen, Sequenzen, Objekt-Attribute in Python sind doch immer Referenzen.

                      Tim

                      1. Hi Tim

                        Mein Perl ist brüchig bis kaum vorhanden, aber wenn Du mit Perl-Listen die Syntax ($a, $b, $c) meinst und Perl-Arrays die Syntax [$a, $b, $c], dann .. sind pythonische Tupel immer noch nicht wirklich Listen im Sinne von Perl, so dass Interpolation statt findet. Im Tupel ist dann immer noch eine Referenz gespeichert:

                        schon klar, ich schrieb bewußt "eher" weil Perl-Listen halt nicht veränderbare Arrays sind, um mit deinen Worten zu sprechen:

                        Idealerweise stellst Du Dir Tupel nicht als „nicht veränderbare Listen“

                        Es gibt aber keine Listenvariablen, man kann Listen einer Arrayvariable zuweisen, aber dann wird daraus ein Array. Wie das Arrray dann wideregegeben wird richtet sich nach Kontext und Sigil.

                        Default, dh kürzeste Schreibweise, ist dabei die Listenform mit dem @, das führt aber leider bei vielen Leuten zu dem Missverständnis Listen und Arrays wären in Perl Synonyme, obwohl es feine Unterschiede gibt.

                        >>> s = 1
                          >>> t = (s, 2)
                          >>> id(s)
                          16790920
                          >>> id(t)
                          420640
                          >>> id(t[0])
                          16790920

                        analog im Perldebugger ( perl -de0)

                          
                          DB<1> $s=1;  
                          
                          DB<2> @t=(\$s,2);  # weise Array t die Liste zu  
                          
                          DB<3> p \$s;   #referenz zu $s  
                        SCALAR(0x83c5d78)  
                          DB<4> p \@t;   #referenz zu @t  
                        ARRAY(0x83b7784)  
                          DB<5> p $t[0];  
                        SCALAR(0x83c5d78)  
                        
                        

                        In Perl kommt man aber sehr selten auf die Idee die Referenz eines Skalars wie $s abzulegen. Das braucht man IMHO so gut wie nie.

                        Die Möglichkeiten sind die selben, die Defaults sind halt andere, in perl muss man explizit refrenzieren um eine Refrenz abzulegen und diese später wieder explizit derefrenzieren.

                        Braucht man Referenzen, kann man die Listenform umgehen und konsistent nur mit Referenzen arbeiten, der Syntax wird aber aufwändiger, weils (leider) nicht default ist.

                          
                          DB<6> $$s_ref=1  
                          
                          DB<7> $t_ref=[$s_ref,2]  
                        #oder:  @$t_ref=($s_ref,2)  
                          DB<8> print $s_ref  
                        SCALAR(0x83c5e20)  
                          DB<9> p $t_ref  
                        ARRAY(0x83c5e14)  
                          DB<10> p $$t_ref[0]  
                        #oder:   p $t_ref->[0]  
                        SCALAR(0x83c5e20)  
                        
                        

                        ... und Perl-Listen kann man nicht schachteln so wie Python-Tupel, sie werden immer abgeflacht. Will man Schachteln muss man Arrayrefrenzen ablegen.

                          
                          DB<18> @A=(1,2,3)  
                          
                          DB<19> @B=(4,5,6,@A)  
                          
                          DB<20> p @B  
                        456123  
                        
                        

                        Aber auch die Rückgabe mehrerer Werte funktuioniert analog zu Python-Tupel über Perl-Listen

                          
                          DB<21> sub func {return 1,2,3}  
                          
                          DB<22> ($a,$b,$c)=func()  
                          
                          DB<23> p $a,$b,$c  
                        123  
                        
                        

                        Alles nur der Vollständigkeit halber, ich denke du kennst Perl gut genug! :)

                        Aber ich denke für die anderen wird klar, das Python-Tupel wohl am ehesten als schachtelbare und ablegbare Perl-Listen beschrieben werden können.

                        Ciao
                         Kurt

                      2. Hi

                        >>> s = 1
                          >>> t = (s, 2)
                          >>> id(s)
                          16790920
                          >>> id(t)
                          420640
                          >>> id(t[0])
                          16790920

                        also, eine Sache verstehe ich hier nicht....
                        dieses Verhalten das t[0] auf die selbe Variable wie s zu referenzieren,
                        würde doch bedeuten (und Sinn machen), dass es sich um Aliase handelt, d.h. eine Änderung von des Inhalts von s würde auch t[0] ändern und vice versa.

                        mit s=2 ändere ich aber auch die id(s) und t[0] behält den alten wert...?!?

                        habe ich was verpasst?

                        Ciao
                         Kurt

                        1. Hallo Kurt,

                          dieses Verhalten das t[0] auf die selbe Variable wie s zu referenzieren,
                          würde doch bedeuten (und Sinn machen), dass es sich um Aliase handelt, d.h. eine Änderung von des Inhalts von s würde auch t[0] ändern und vice versa. mit s=2 ändere ich aber auch die id(s) und t[0] behält den alten wert...?!?

                          Wenn Du s auf ein neues Int-Objekt mit dem Wert 2 zeigen lässt, dann hat s eben eine neue Referenz auf ein anderes Objekt. t[0] zeigt weiterhin stabil und unveränderbar auf das originale Objekt; hat deswegen noch immer die gleiche ID:

                          >>> s = 1
                            >>> id(s)
                            16790920
                            >>> t = (s, 2)
                            >>> id(t[0])
                            16790920
                            >>> s = 2
                            >>> id(s)
                            16790908
                            >>> id(t[0])
                            16790920

                          Zahlen (und Strings .. und Tupel) sind in Python unveränderbar, jede Operation auf diese hat eine neue, keine geänderte Zahl und damit ein neues, anderes und kein geändertes Objekt zur Folge. Lustiger wird es, wenn man einen veränderbaren Objekt-Typ nimmt:

                          >>> li = [1, 2]
                            >>> id(li)
                            420480
                            >>> t = (li, "foo")
                            >>> t
                            ([1, 2], 'foo')
                            >>> id(t[0])
                            420480
                            >>> li[0] = "bar"
                            >>> li
                            ['bar', 2]
                            >>> id(li)
                            420480
                            >>> t
                            (['bar', 2], 'foo')
                            >>> id(t[0])
                            420480

                          Die Unveränderbarkeit des Tupels bezieht sich also auf die darin enthaltenen Referenzen, nicht auf die gesamte referenzierte Struktur selbst.

                          Tim

                          1. Hi

                            Zahlen (und Strings .. und Tupel) sind in Python unveränderbar, jede Operation auf diese hat eine neue, keine geänderte Zahl und damit ein neues, anderes und kein geändertes Objekt zur Folge.

                            was hilft mir dann die Info welche Objekt-ID eine Zahl hat wenn das Objekt unveränderbar ist?

                            Grüße
                             kurt

                            1. Hallo,

                              was hilft mir dann die Info welche Objekt-ID eine Zahl hat wenn das Objekt unveränderbar ist?

                              Es sollte Dir nur sagen, dass die Referenz im Tupel immer noch vorhanden ist.

                              Tim

  3. Hallo,

    warum gibt in JavaScript [1] == [1] false aber 1 == 1 true aus?

    Zur Ergänzung:
    ECMAScript: The Abstract Equality Comparison Algorithm
    Das läuft bei zwei Arrays darauf hinaus:
    »Return true if x and y refer to the same object or if they refer to objects joined to each other (see 13.1.2). Otherwise, return false.«
    (Joint objects habe ich noch nie gesehen. Das gibts wohl in der Praxis nicht.)

    Mathias

  4. gruss Jeena,

    hier noch der hinweis auf meinen senf zur ergaenzung
    aller schon erfolgten wortmeldungen:

    »[Object].equals, [Object].dump, [Object].clone«

    so long - peterS. - pseliger@gmx.net

    --
    »Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
    Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - Douglas Crockford
    ie:( fl:) br:> va:( ls:& fo:) rl:) n3;} n4:} ss:} de:µ js:} mo:? zu:]
    1. ... aehm, *huestel* ... entschuldigung ...

      danke fuer den link, Christian - das naechste mal folge ich auch
      allen im thtread angegebenen links, um so eine doppelte referenz
      zu vermeiden ...

      ... versprochen - peterS.

    2. Hallo peterS,

      »Object.equals, Object.dump, Object.clone«

      Das habe ich mir kurz angesehen. Sehr interessant, denn mich interessieren vor allem scheinbar unlösbare Problemee :-). Habe selbst einmal eine object.clone() Methode gebastelt, eine recht einfache, und bin ganz zufrieden damit. Allerdings geschah das nicht im Hinblick auf eine Object.equals() Methode.

      Du schreibst dort:
      "wer es schafft, fuer JavaScript ein wasserdichtes [Object].clone und ein verlaessliches [Object].equals zu schreiben, muss diese sprache fast schon verinnerlicht haben."

      Kannst du nochmal kurz schildern, wo genau das Problem liegt, z.B. für ein "wasserdichtes [Object].clone"? Es gibt zwar viel "Quälcode" (very funny) dort, aber wenig Doku, die erklären würde, wozu die Kapriolen eigentlich gemacht werden.

      Danke und Gruß, Don P

      1. gruss Don P,

        ...
        Das habe ich mir kurz angesehen. Sehr interessant, denn mich
        interessieren vor allem scheinbar unlösbare Problemee : -).

        ...

        Du schreibst dort:

        ...

        Kannst du nochmal kurz schildern, wo genau das Problem liegt,
        z.B. für ein "wasserdichtes [Object].clone"? Es gibt zwar viel
        "Quälcode" (very funny) dort, aber wenig Doku, die erklären
        würde, wozu die Kapriolen eigentlich gemacht werden.

        mache ich - vorweg aber erstmal die erklaerungen fuer [equals] und [dump]:

        wie schon vielfach erlaeutert, lassen sich JavaScript-objekte genau
        dann nicht mehr verlaesslich miteinander vergleichen, sobald fuer
        einen vergleich sowohl mit dem gleichheits- [==] als auch mit dem
        identitaetsoperator [===] keine objektreferenzen mehr herangezogen
        werden koennen.

        in diesem fall muss man eine art "signatur" fuer jedes der beiden
        objekte fuer den vergleich bemuehen.

        diese im folgenden [dump] genannte methode, sollte sich in ihrer
        grundfunktionalitaet an die von der mozilla.org implementierten
        [toSource]-methode anlehnen, muss aber ueber diese hinaus auch der
        tatsache rechnung tragen, dass objekte eben nicht allein durch
        initilisierende konstruktor-aufrufe beschrieben werden koennen,
        sondern immer auch hash-verhalten an den tag legen.

        darueber hinaus erschwert die vermischung von JavaScript-api
        (sprachkern) und DOM-api (dokument) das vergleichende geschaeft.

        der [dump] beschreibt bzw. identifiziert elemente des DOM deswegen
        in dieser reihenfolge anhand ihrer id-, tagName-, name-getter. noch
        nicht ins DOM eingefuegte knoten-fragmente muessen ihr [innerHTML]
        offenlegen.

        fuer [clone] muss aehnlich vorgegangen werden, wenn man nicht der
        Crockfordschen/Confordschen*[1] schule folgen will, in der das zu
        kopierende object als prototyp eines anonymen und *leeren* konstruktors
        referenziert wird - frei nachempfunden, aber prinzipiell so:

        var object = (function (obj) {  
          
         var cnstr = new Function();  
         cnstr.prototype = obj;  
          
         return (new cnstr());  
        });  
          
        var arr = ["hallo", "welt"];  
        var obj = object(arr);  
          
        alert("arr : " + arr + "\nobj : " + obj + "\n(arr == obj) ? " + (arr == obj));  
        alert("(arr.toString() === obj.toString()) ? " + (arr.toString() === obj.toString()));  
        alert("(\"" + arr.join(" ") + "\" === \"" + obj.join(" ") + "\") ? " + (arr.join("! ") === obj.join("! ")));  
          
          
        /*  
          bitte copy und paste nach [[link:http://jconsole.com/]]  
        */
        

        *[1] - Douglas Crockford / Richard Conford

        zurueck vom ausflug - weiter mit dem versuch moeglichst ideal zu klonen:

        die [clone]-methode wird jedem build-in-typen - [Boolean], [Number], [String],
        [Date], [Error], [RegExp], [Function] und schlussendlich allgemein [Object]
        (was [Array] mit einschliesst) einzeln *verbacken* - warum?

        im (rekursiven) clone-prozess verlaesst man sich zurecht darauf, dass das
        weitgehend unbekannte objekt am besten ueber seine instanziierungs-geschichte,
        seine prototypen-kette und erst zuletzt ueber seinen konstruktor *bescheid weiss*
        und demzufolge die *richtige* clone methode in ebendieser reihenfolge automatisch
        abgegriffen werden kann. dabei wird der erfolg einer instanziierung ueberwacht
        und zuletzt gegebenenfalls auf den zu erwartenden konstruktor/typ zurueckgegriffen.

        im nachfolgenden wiederum rekursiven aufbau der jeweils ersten objektebene
        werden ausschliesslich nicht [prototype]-eigenschaften zugelassen. fuer diese
        wird nach einer im sinne von JavaScript "nativen"*[2] [clone]-methode gesucht.
        scheitert das projekt an dieser stelle kann das ergebnis einer vollstaendigen
        iteration nicht mehr als *echter clone" bezeichnet werden, denn die nachfolgenden
        fallbacks nehmen dann das was kommt - zuerst wird das nicht native [clone] probiert,
        dannach wird nur noch referenziert.

        *[2] siehe [this.isNative] aus [http://www.pseliger.de/jsExtendedApi/jsApi.Object.typeDetection.new.dev.js]:

        this.isUndefined = function (obj) {  
          return (typeof obj == "undefined");  
        };  
        this.isNull = function (obj) {  
          return ((typeof obj == "object") && (!obj));  
        };  
          
        this.isValue = function (obj) {  
          return ((typeof obj == "string") || (typeof obj == "number") || (typeof obj == "boolean"));  
        };  
        this.isObject = function (obj) {  
          return (obj && (typeof obj == "object"));  
        };  
          
        this.isNative = function (obj) {  
          return (!isUndefined(obj) && !isNull(obj) && (typeof obj.constructor == "function"));  
        };  
        this.isAlien = function (obj) {  
          return (isObject(obj) && (typeof obj.constructor != "function"));  
        };
        

        so long - peterS. - pseliger@gmx.net

        --
        »Because objects in JavaScript are so flexible, you will want to think differently about class hierarchies.
        Deep hierarchies are inappropriate. Shallow hierarchies are efficient and expressive.« - Douglas Crockford
        ie:( fl:) br:> va:( ls:& fo:) rl:) n3;} n4:} ss:} de:µ js:} mo:? zu:]