Don P: Garbage Collection oder was?

Hallo,

Code-Teile, die ich mit viel Hirnschmalz ausgetüftelt und getestet habe, notiere ich gern in möglichst kurzer Form. Wenn ich später in meinem Code etwas sehe wie

  
setCols: function(csn){for(var c0,c1,hh=new Array(this.atPos.length),i=0;i in this.atPos;i++){c1=(i+1)%csn||csn;c0=+i?(c1-1)||csn:c1;hh[i]={n0:c0,n1:c1,h0:i,h1:36-i};}this.cHits=hh;this.cNums=this.setCols(csn);return hh;}

dann weiß ich gleich: "bloß nicht mehr anfassen, das funktioniert".
Beim Verkürzen ist mir aufgefallen, dass man z.B. folgendes

  
for (csn in cs) {  
    if (cs[csn].active) {  
        if (cs[csn].bestFix) {cs[csn].bestClick();}  
        else {cs[csn].sysScan();}  
    }  
}  

auch so notieren kann:

  
for (csn in cs) { cs[csn].active && ( cs[csn].bestFix ? cs[csn].bestClick() : cs[csn].sysScan() ) }  

In der for-Schleife steht jetzt nur noch ein Ausdruck, kein Befehl oder Zuweisung oder so. Das Ergebnis des Ausdrucks (Inhalt von cs[csn].active oder ein Funktionsergebnis) landet sozusagen im Nirwana, wird ja auch nicht weiter benötigt.

Frage an ECMAscript-Kenner:
Wird damit nicht vielleicht der Garbage-Collector überstapaziert (wenn man ständig so codet), oder ist das legitim, weil ja eigentlich der Interpreter gleich erkennen kann bzw. könnte, was da zu tun ist (nämlich das Ergebnis verwerfen)?

Danke und Gruß, Don P

  1. Jedes Ergebnis, dass nicht innerhalb der Anweisung aufgefangen wird, landet sofort im Orkus (bzw. bei Firebug in der Console) und ist bereits beim nächsten Durchgang nicht mehr verfügbar sein.

    Gruß, LX

    --
    RFC 1925, Satz 6a: Es ist immer möglich, einen weiteren Umweg einzufügen.
    RFC 1925, Satz 11a: Siehe Regel 6a
    1. Hallo,

      Jedes Ergebnis, dass nicht innerhalb der Anweisung aufgefangen wird, landet sofort im Orkus

      Aha, dann ist es also ok so.
      Nicht, dass mir noch der Rechner abraucht, weil die vielen nicht abgeholten Bits und Bytes seitlich aus dem Prozessor quellen... ;-)

      Danke, Don P

      1. Das kommt immer darauf an, wie schnell der Müllwagen von Deinem Garbage Collector fährt... beim MSIE wird der ja angeblich noch von einzelnen Zwerghamstern angetrieben...

        Gruß, LX

        --
        RFC 1925, Satz 6a: Es ist immer möglich, einen weiteren Umweg einzufügen.
        RFC 1925, Satz 11a: Siehe Regel 6a
  2. Hi,

    auch so notieren kann:

    for (csn in cs) { cs[csn].active && ( cs[csn].bestFix ? cs[csn].bestClick() : cs[csn].sysScan() ) }

    
    >   
    > Frage an ECMAscript-Kenner:  
    > Wird damit nicht vielleicht der Garbage-Collector über strapaziert (wenn man ständig so codet), oder ist das legitim, weil ja eigentlich der Interpreter gleich erkennen kann bzw. könnte, was da zu tun ist (nämlich das Ergebnis verwerfen)?  
      
    Man kann natürlich so coden, solange es irgendeinen Vorteil bietet. Bei dem obigen Beispiel sehe ich den Nachteil, dass es zu kryptisch ist und man schneller andere Fehler macht.  
      
    Bei deinem unteren Beispiel fehlt ein einfaches Semikolon. Das sorgt dafür, dass der Interpreter bei jedem Schleifendurchgang nach einem false oder was auch immer deine Funktionen zurück geben ein Semikolon sucht, aber } findet. Dann muss er das Semikolon selber setzten und kann dann erst den Code ausführen. Dass im Falle von !cs[csn].active ein false; entsteht ist dabei nicht gravierend.  
      
    Den größten Fehler machst du schon am Anfang der Schleife. Da vor dem csn kein var steht, durchsucht der Interpreter erst die ganze Scopechain bis zu global nach einer Variablen Namens "csn". Da wahrscheinlich keine gefunden wird, fügt der Interpreter ein var ein und erstellt eine neue Variable. Beim verlassen der Schleife wird dann csn vom GarbeCollector wieder freigegeben.  
      
    Ich empfehle dir diese Schreibweise:  
      
    ~~~javascript
    for( var csn in cs){  
        cs[csn].active&& ( cs[csn].bestFix? cs[csn].bestClick(): cs[csn].sysScan());  
    }
    

    MfG Hase

    1. Kleine Korrektur: der Interpreter fügt kein var ein, sondern legt die Variable gleich als Instanz von window ab.

      Ansonsten hast Du völlig Recht, lediglich die ; vs. } Geschichte wird nicht von allen Parsern so behandelt: neuere Engines handeln dieses Problem in einem Durchgang ab.

      Gruß, LX

      --
      RFC 1925, Satz 6a: Es ist immer möglich, einen weiteren Umweg einzufügen.
      RFC 1925, Satz 11a: Siehe Regel 6a
      1. Hi,

        Kleine Korrektur: der Interpreter fügt kein var ein, sondern legt die Variable gleich als Instanz von window ab.

        Was somit noch schlimmer ist als ich dachte. Dann hat man ja csn im Raum rumstehen.

        Ansonsten hast Du völlig Recht, lediglich die ; vs. } Geschichte wird nicht von allen Parsern so behandelt: neuere Engines handeln dieses Problem in einem Durchgang ab.

        Was dann aber auch kein Grund sein sollte es wegzulassen.

        Wieder mal was neues gelernt.

        MfG Hase

    2. Hallo,

      Man kann natürlich so coden, solange es irgendeinen Vorteil bietet. Bei dem obigen Beispiel sehe ich den Nachteil, dass es zu kryptisch ist und man schneller andere Fehler macht.

      Das ist doch gerade die Absicht, dass es kryptisch aussieht, damit man nicht in Versuchung kommt, nachträglich nochmal darin rumzupfuschen. Solche extremen Zeilen gibt's bei mir nur in schwierigen Programmteilen, die ich möglichst nicht mehr verändern will. Wenn das Programm in der weiteren Entwicklung mal nicht tut, was es soll, dann liegt's sicher nicht an diesen Zeilen, denn die sind bis zum Abwinken getestet und für gut befunden.
      Das sehe ich als Vorteil.

      Bei deinem unteren Beispiel fehlt ein einfaches Semikolon. [...]

      Das ist interessant. Dachte, ein Semikolon braucht man nur, um eine Anweisung abzuschließen. Ein Ausdruck wie a||b ist aber doch keine Anweisung. Werde das Semikolon aber trotzdem setzen. Performance-Gewinn ist immer gut. :-)

      Da vor dem csn kein var steht, durchsucht der Interpreter erst die ganze Scopechain [...]

      Neinnein, globale Variablen gibt's bei mir nicht. Das Beispiel ist ja nur ein Codeschnipsel. csn wurde vorher schon lokal deklariert. Ansonsten schreibe ich natürlich immer das var dazu.

      Der eizige Fall, wo ich eine globale Variable brauche, ist bei Benutzung von setTimeout. Habe bis jetzt keinen Weg gefunden, mit setTimeout etwas zu starten, was nicht irgendie global verfügbar ist...

      Danke und Gruß, Don P

      1. Hi,

        Das ist doch gerade die Absicht, dass es kryptisch aussieht, damit man nicht in Versuchung kommt, nachträglich nochmal darin rumzupfuschen.

        Das ist doch gerade das idiotische.

        Solche extremen Zeilen gibt's bei mir nur in schwierigen Programmteilen, die ich möglichst nicht mehr verändern will.

        Und wenn du doch mal *musst*?

        Wenn das Programm in der weiteren Entwicklung mal nicht tut, was es soll, dann liegt's sicher nicht an diesen Zeilen, denn die sind bis zum Abwinken getestet und für gut befunden.

        Diese Info kann man in einem Kommentar unterbringen.

        Das sehe ich als Vorteil.

        Ich als, siehe oben, leichten Anfall von Idiotie :-)

        MfG ChrisB

        --
        Light travels faster than sound - that's why most people appear bright until you hear them speak.
        1. Hallo,

          Solche extremen Zeilen gibt's bei mir nur in schwierigen Programmteilen, die ich möglichst nicht mehr verändern will.

          Und wenn du doch mal *musst*?

          Dann gehe ich zur Toilette.
          Nein, im Ernst: Dann zerpflücke ich das Ding halt wieder! Aber natürlich erst nach reiflicher Überlegung. Warum sollte man z.B. eine gute shuffle-Funktion für Arrays jemals verändern *müssen*?

          Wenn das Programm in der weiteren Entwicklung mal nicht tut, was es soll, dann liegt's sicher nicht an diesen Zeilen, denn die sind bis zum Abwinken getestet und für gut befunden.

          Diese Info kann man in einem Kommentar unterbringen.

          Ja sicher, kann man. Zur Zeit hat mein Projekt ca. 1500 Zeilen. Ohne solche Komprimierungen wären es weit mehr, und Kommentare mache das ganze auch nicht gerade übersichtlicher.

          Das sehe ich als Vorteil.

          Ich als, siehe oben, leichten Anfall von Idiotie :-)

          Danke. Werde das mal bei meinem Psychiater erwähnen...

          Gruß, Don P

          1. Hi,

            Nein, im Ernst: Dann zerpflücke ich das Ding halt wieder! Aber natürlich erst nach reiflicher Überlegung. Warum sollte man z.B. eine gute shuffle-Funktion für Arrays jemals verändern *müssen*?

            Und warum sollte man sie möglichst kryptisch notieren?

            Diese Info kann man in einem Kommentar unterbringen.

            Ja sicher, kann man. Zur Zeit hat mein Projekt ca. 1500 Zeilen. Ohne solche Komprimierungen wären es weit mehr, und Kommentare mache das ganze auch nicht gerade übersichtlicher.

            Natürlich machen Kommentare Scripte übersichtlicher - wenn man sie vernünftig benutzt.

            MfG ChrisB

            --
            Light travels faster than sound - that's why most people appear bright until you hear them speak.
            1. Hi,

              Nein, im Ernst: Dann zerpflücke ich das Ding halt wieder! Aber natürlich erst nach reiflicher Überlegung. Warum sollte man z.B. eine gute shuffle-Funktion für Arrays jemals verändern *müssen*?

              Und warum sollte man sie möglichst kryptisch notieren?

              Damit man nicht in die Versuchung kommt diese zu ändern. Der Programmierer ist von Grund auf Faul :) und bevor er sich das antut, alles auseinander zu pflücken, wird er sozusagen gezwungen etwas mehr über sein Problem und das erreichen seines Ziels nachzudenken. Und vielleicht findet sich dann eine andere Lösung?

              1. Hallo,

                Damit man nicht in die Versuchung kommt diese zu ändern. Der Programmierer ist von Grund auf Faul :) und bevor er sich das antut, alles auseinander zu pflücken, wird er sozusagen gezwungen etwas mehr über sein Problem und das erreichen seines Ziels nachzudenken. Und vielleicht findet sich dann eine andere Lösung?

                Eben. Es geht einfach darum, nicht leichtfertig mit dem A.... wieder umzustoßen, was man vorher mühsam mit den Händen erschaffen hat. ;-))

                Gruß, Don P

      2. Hi,

        Wenn das Programm in der weiteren Entwicklung mal nicht tut, was es soll, dann liegt's sicher nicht an diesen Zeilen, denn die sind bis zum Abwinken getestet und für gut befunden.

        Das halte ich zwar für gewagt, aber wenn es bei dir klappt, dann mach es so.

        Bei deinem unteren Beispiel fehlt ein einfaches Semikolon. [...]

        Das ist interessant. Dachte, ein Semikolon braucht man nur, um eine Anweisung abzuschließen. Ein Ausdruck wie a||b ist aber doch keine Anweisung.

        Javascript hat solche Ausdrücke leider von C geerbt. Dort waren sie kein Problem, hier aber schon. JSLint gibt mir recht, dass dort ein Semikolon hin muss. Vor allem, wenn du dein Script auf den kommenden Strictmode vorbereiten willst, brauchst du das Semikolon.

        Da vor dem csn kein var steht, durchsucht der Interpreter erst die ganze Scopechain [...]

        Neinnein, globale Variablen gibt's bei mir nicht. Das Beispiel ist ja nur ein Codeschnipsel. csn wurde vorher schon lokal deklariert. Ansonsten schreibe ich natürlich immer das var dazu.

        Wenn du das csn wirklich außerhalb der Schleife dringend benötigst, kannst du es so machen. Ansonsten würde ich dir aber empfehlen es im Schleifenkopf zu definieren, damit der Speicher beim Verlassen der Schleife wieder freigegeben werden kann.

        MfG Hase

        1. Hallo,

          Wenn du das csn wirklich außerhalb der Schleife dringend benötigst, kannst du es so machen. Ansonsten würde ich dir aber empfehlen es im Schleifenkopf zu definieren, damit der Speicher beim Verlassen der Schleife wieder freigegeben werden kann.

          Der Speicher wird aber nicht freigegeben. Eine Deklaration im Schleifenkopf wirkt meines Wissens wie jede andere in der aktuellen Prozedur. Das ist nur eine kosmetische Sache. csn existiert auch nach Beenden der Schleife weiter.

          Gruß, Don P

    3. Hallo Hase,

      Ich empfehle dir diese Schreibweise:

      for( var csn in cs){

      cs[csn].active&& ( cs[csn].bestFix? cs[csn].bestClick(): cs[csn].sysScan());
      }

        
      Da fällt mir noch etwas ein:  
      Es wird ja ggf. viermal auf cs[csn] zugegriffen. Ist es da nicht besser (d.h. schneller), wenn man so notiert:  
        
      ~~~javascript
        
      var csn, cs, css=this.css;  
      for (csn in css) { var cs=css[csn]; cs.active && ( cs.bestFix ? cs.bestClick() : cs.sysScan() ); }  
      
      

      Durch Initialisieren von cs am Anfang der for-Schleife könnte der Zugriff auf das Objekt css[csn] doch einfacher werden, oder?
      Normalerweise benutze ich immer so eine lokale Variable, wenn mehr als ein Zugriff auf ein Unterobjekt bzw. Array nötig wird. Aber macht das performancemäßig wirklich Sinn? Vielleicht verlangsamt das ja auch die Sache durch die zusätzliche(n) Anweisung(en)...

      Gruß, Don P

      1. Hi,

        Da fällt mir noch etwas ein:
        Es wird ja ggf. viermal auf cs[csn] zugegriffen. Ist es da nicht besser (d.h. schneller), wenn man so notiert:

        var csn, cs, css=this.css;
        for (csn in css) { var cs=css[csn]; cs.active && ( cs.bestFix ? cs.bestClick() : cs.sysScan() ); }

          
        Ich weiß leider nicht in welchem Verhältnis `this.css`{:.language-javascript} zu cs steht. Deswegen halte ich die erste Zeile erstmal für Quatsch.  
          
        Ob `var cs=css[csn];`{:.language-javascript} dir einen Geschwindigkeitsvorteil bietet hängt ganz vom Verhältnis von den Elementen mit .active zu denen ohne ab( bzw, von denen mit .active==true zu denen mit .active==false).  
          
        MfG Hase  
        
        
        1. Hallo,

          Ich weiß leider nicht in welchem Verhältnis this.css zu cs steht. Deswegen halte ich die erste Zeile erstmal für Quatsch.

          css ist ein Objekt (hat nichts mit CCS-stylesheets zu tun), das einige Unterobjekte als Eigenschaften enthält, auf die in der Schleife zugegriffen werden soll. Diese Unterobjekte haben jeweils u.a. die Eigenschaften active und bestFix.

          Ob var cs=css[csn]; dir einen Geschwindigkeitsvorteil bietet hängt ganz vom Verhältnis von den Elementen mit .active zu denen ohne ab( bzw, von denen mit .active==true zu denen mit .active==false).

          Ok, in diesem Beispiel ist es nicht so klar.

          Allgemein: Ist der wiederholte Zugriff auf ein Objekt a[b].c.d[e] einfacher (schneller), wenn man es zuerst mit var o=a[b].c.d[e] in einer lokalen Variablen speichert, oder nicht?
          Immerhin wäre das eine zusätzliche Anweisung, und vielleicht ist die Engine ja so schlau, dass sie nicht bei jedem Zugriff die ganze Kette von a bis e durchläuft, sondern sich den Wert ohnehin nach dem ersten Zugriff merkt...

          Gruß, Don P

          1. Hi,

            Allgemein: Ist der wiederholte Zugriff auf ein Objekt a[b].c.d[e] einfacher (schneller), wenn man es zuerst mit var o=a[b].c.d[e] in einer lokalen Variablen speichert, oder nicht?

            Ja. Man sollte möglichst vermeiden, dass der Punkt-Operator wiederholt für das gleiche zum Einsatz kommt.

            Immerhin wäre das eine zusätzliche Anweisung, und vielleicht ist die Engine ja so schlau, dass sie nicht bei jedem Zugriff die ganze Kette von a bis e durchläuft, sondern sich den Wert ohnehin nach dem ersten Zugriff merkt...

            Darauf würde ich mich nicht verlassen.
            Allerdings möglich, dass aktuelle Engines auch in der Hinsicht selber optimieren.

            MfG ChrisB

            --
            Light travels faster than sound - that's why most people appear bright until you hear them speak.
  3. auch so notieren kann:

    for (csn in cs) { cs[csn].active && ( cs[csn].bestFix ? cs[csn].bestClick() : cs[csn].sysScan() ) }

    
    > In der for-Schleife steht jetzt nur noch ein Ausdruck, kein Befehl oder Zuweisung oder so. Das Ergebnis des Ausdrucks (Inhalt von `cs[csn].active`{:.language-javascript} oder ein Funktionsergebnis) landet sozusagen im Nirwana, wird ja auch nicht weiter benötigt.  
    >   
    > Frage an ECMAscript-Kenner:  
    > Wird damit nicht vielleicht der Garbage-Collector überstapaziert (wenn man ständig so codet), oder ist das legitim, weil ja eigentlich der Interpreter gleich erkennen kann bzw. könnte, was da zu tun ist (nämlich das Ergebnis verwerfen)?  
      
    Ich find den Ausdruck gut, aber ich wüßte nicht inwiefern der GC da in irgendeiner Art  betroffen ist. Das ein Ergebnis nicht verwendet wird, ist Alltag und keine Besonderheit für den GC.  
      
    Struppi.