Tag Archives: Programming - Page 2

Mehr Spaß mit JavaScript

Was ist das mit dieser Sprache? Man findet im Web mehrere Stellen, die die Existenz einer solche Schleife in JavaScript postulieren:

for each ( element in array ) {
  ...
}

Die Tatsache, dass das Syntaxhighlighting das each nicht hervorhebt, hätte mich stutzig machen müssen. Später stellte ich fest, dass eine solche Schleife auf einem k-elementigen Array k+1 Mal durchlaufen wird, zuletzt mit element === null. Heute komme ich durch einen Hinweis von Frank darauf, dass doch tatsächlich Opera diese Schleifen gar nicht kennt.

Also bin ich meinen Code durchgegangen und habe alle for-each-Schleifen durch gute alte Zählschleifen ersetzt, kein Problem soweit. Nur, dass nun auf einmal Endlosschleifen auftraten. Ich kann das Problem an meinem Code nicht mehr reproduzieren, aber es lag wohl ein Fehler dieser Art vor. Was ist das für eine Sprache bzw. ein Interpreter, die bzw. der sowas erlaubt?!

Jedenfalls steht jetzt in jeder Schleifen ein var, und das ist auch gut so. Arg.

Probleme mit der Gültigkeit von Variablen in JavaScript

Bei meinem aktuellen Bastelprojekt habe ich mich in die Tiefen von AJAX gestürzt. Ich hab schon viel geflucht, aber das hier ist die Krönung.

Man stelle sich vor, man möchte an einer Reihe von gleichartigen Elementen Listener registrieren, sodass an jedem Element eine leicht veränderte Aktion ausgeführt wird. Das geht zum Beispiel mit prototype an sich ziemlich einfach. Es kommt unter Umständen folgener Code heraus (der hier natürlich auf das Essentielle vereinfacht ist):

for ( i=0; i<4; i++ ) {
  var j = 2*i;
  $('button_' + i).observe('click', function (event) { alert(j); });
}

Dieses unschuldige Stückchen Code hat aber nicht den gewünschten Effekt. Jeder Button meldet ’6′. Das ist verwirrend, denn jeder Button bekommt seine eigene Funktion, die von einem Wert abhängt, der ganz sicher auch nur für die Konstruktion dieser einen Funktion benutzt wird. Natürlich muss j nach Ende jeder Iteration weiterleben, damit die anonym definierte Funktion einen sinnvollen Kontext hat. Letztenendes muss es also vier Instanzen von j geben, die alle die Schleife überdauern.
Ich vermute, dass der Interpreter meint, zu optimieren, indem er j immer wieder überschreibt. In vielen Fällen mag das sinnvoll sein, wenn j nämlich nach Ende einer Iteration tatsächlich nicht mehr lebt. Hier sind aber wirklich vier Instanzen nötig.

Man kann das nun in den Griff bekommen, indem man zum Beispiel so arbeitet:

for ( i=0; i<4; i++ ) {
  var j = 2*i;
  $('button_' + i).observe('click', clicked(j));
}

function clicked(i) {
  return function(event) { alert(i); };
}

Ist das ein Bug von Javascript oder nur von Firefox (3.0.8) oder ist das ein Feature und ich bin zu dämlich?

Codebeispiele hier.

Daten mit JSON repräsentieren

Spätestens seit dem Softwareentwicklungspraktikum habe ich eine gefühlte Lücke in meiner gedanklichen Werkzeugkiste: Wie repräsentiere ich einfache Daten mit wenig Aufwand möglichst gut lesbar für Mensch und (verschiedene) Maschinen?

Die heute kanonische Antwort scheint stets XML als standardisiertes Metadatenformat mit vielfältiger Toolunterstützung zu sein. In manchen Fällen mag das gerechtfertigt sein, mir erschien der Overhead insbesondere bei einfachen Datenstrukturen aber unangebracht; insbesondere das Monster DomParser hat uns viele Flüche entlockt. Wir stiegen dann auf JDOM um, was zumindest eine angenehmere Bibliothek ist, aber natürlich am sperrigen Datenformat nichts ändert. Auch sind XML-Sprachen oft kaum bis gar nicht lesbar, weil man sich durch abstrakte Elemente und Namespaces wühlen muss.

Beim Prokrastinieren fand ich heute Hinweise auf JSON. Diese schlanke Sprache füllt meine Lücke insofern, als dass sie für die meisten Daten relativ simpler Struktur ein sehr einfaches Darstellungsformat bietet, das für jeden Programmierer intuitiv verständlich sein sollte. Dabei geht es von Objekten aus, die sich durch Paare aus Schlüsseln und Werten auszeichnen. Andere Objekte sind dabei als Werte natürlich erlaubt. So könnte man zum Beispiel formulieren:

{
  "titel" : "Beispielbuch",
  "autoren" : ["Max M.", "Jutta J."],
  "isbn" : 123456789,
  "verlag" : {
    "name" : "Beispielverlag",
    "ort" : "Musterstadt"
  },
  "taschenbuch" : false
}

Würde man XML nutzen wollen, sähe das vielleicht so aus:

BeispielbuchMax M.Jutta J.123456789BeispielverlagMusterstadtfalse

Hier missfällt mir spontan, dass nicht klar ist, ob man einen Wert nun als Element oder Attribut modellieren sollte. Auch fällt direkt auf, dass viel Text nur für die Strukturierung der Daten mit Tags aufgebracht werden muss und so die Lesbarkeit verschlechtert.

Die offizielle Homepage liefert umfassende Informationen zu JSON und eine Liste mit vielen Sprachen, für die bereits Bibliotheken für die Arbeit mit JSON existieren. Ganz unten finden sich noch einige Links zu interessanten Beiträgen unter anderem zur Diskussion “XML vs. JSON”.

Ich bin froh, JSON heute entdeckt zu haben, und werde bei nächster sich bietenden Gelegenheit austesten, wie es sich in ein System integrieren lässt. Eine Allzweckwaffe ist JSON sicher nicht: Da es eine reine Syntaxdefinition ist, gibt es keine Semantik hinter der Darstellung. Jegliche Form von Restriktionen an Daten muss daher von jedem verarbeitenden Programm selbst validiert werden; ein universeller Validator, wie es ihn für XML gibt, ist nicht denkbar. In Kontexten, wo man sich auf die Einhaltung von Konventionen verlässt, ist das möglicherweise aber ohnehin nicht nötig.

Wettlauf der Compiler

Der Fefe macht etwas (für mich) interessantes und sammelt Code in verschiedenen Sprachen für ein simples Problem:

Die Aufgabenstellung ist: stdin lesen, in Wörter splitten, für die Wörter dann jeweils die Häufigkeit zählen, am Ende die Wörter mit Häufigkeiten nach letzteren sortiert ausgeben.

Außerdem fordert er, dass der Code relativ natürlich für die jeweilige Sprache ist, also so, wie man ihn normalerweise, also ohne Wettbewerb, auch schreiben würde. Mitmachen ist erwünscht, so kann jeder Code in einer beliebigen Sprache einreichen.

Damit vergleicht er natürlich hauptsächlich die Implementierungen, wobei sich da mit der Zeit wohl halbwegs sprachoptimale Lösungen einfinden werden. Dann bleibt wohl der Wettstreit von einerseits Sprachkonzepten, andererseits aber auch der Qualität von Compilern und Interpretern. Aktuell steht es so:

  Implementation	Mem/MB	Time

  C++/Boost		381	7.36s user 1.55s system 99% cpu 8.921 total
  C++ (g++ 4.3.2)	390	11.30s user 0.35s system 100% cpu 11.653 total
  C (gcc 4.3.2)		171	12.78s user 0.24s system 99% cpu 13.022 total
  Java 1.6.0_11		56	14.88s user 0.18s system 100% cpu 14.963 total
  Perl 5.10.0		578	14.87s user 0.49s system 100% cpu 15.360 total
  PHP 5.2.7		398	22.79s user 1.71s system 98% cpu 24.793 total
  C# (mono 2.0.1)	498	25.53s user 3.12s system 99% cpu 28.749 total
  sh				25.63s user 1.43s system 100% cpu 27.011 total
  OCaml 3.11.0		414	27.30s user 0.53s system 99% cpu 27.837 total
  Python 2.6.1		529	27.47s user 0.38s system 100% cpu 27.849 total
  Lua 5.1.4		1293	30.44s user 1.44s system 99% cpu 31.900 total
  Tcl 8.5.5		1917	41.31s user 2.07s system 99% cpu 43.388 total
  Ruby 1.9.1preview1	537	54.10s user 0.32s system 99% cpu 54.439 total
  Scheme (MZ 4.1.3)	948	60.50s user 1.91s system 99% cpu 1:02.46 total
  Java (gcj 4.3.2)		72.98s user 0.39s system 99% cpu 1:13.38 total
  Ruby 1.8.7pl72	643	80.57s user 0.39s system 99% cpu 1:21.02 total
  Haskell (ghc 6.10.1)	1450	50.34s user 0.74s system 99% cpu 51.112 total
  mawk 1.3.3		225	135.40s user 0.67s system 100% cpu 2:16.05 total

Nicht sehr überraschend ist, dass Skriptsprachen tendenziell hinter kompilierten Sprachen zurückbleiben, wobei sich Perl sehr stark zeigt – mit riesigem Speicherbedarf.

Interessant finde ich aber, dass der gcj so weit hinter der Maschine von Sun zurückbleibt und auch, dass für C++ anscheinend zwar eine sehr schnelle, aber auch relativ speicherintensive Implementierung gefunden wurde, wobei Java, nun ja, nicht nennenswert schlechter als C(++) ohne Boost ist, aber anscheinend seinen Speicher sehr gut im Griff hat. Da die Implementierungen aber per se nicht direkt vergleichbar sind, bleibt abzuwarten, was sich da noch so entwickelt.

Was mich noch interessieren würde, wäre weniger die Laufzeit für eine große Eingabe, sondern wie sie sich für verschieden große Eingaben verhält.