Kompottkins Weisheiten

••• NEU! Jetzt ohne regelmäßige Serverabstürze! •••

Google Street View vs. Gemeinden

Radio Oberland (13.8.2010):

Der Streit um die Einführung des umstrittenen Kartendienst[es] "Street View" des Internetunternehmens Google auch im Oberland nimmt kein Ende ... Aber auch schon viele Gemeinden in der Region, wie zum Beispiel Herrsching oder Seeshaupt sagen Google den Kampf an.

Natürlich: Die Diskussion über die Wahrung der Privatssphäre durch Konzerne (sowie durch den Staat!) muß geführt werden, allein schon um die Bevölkerung für das Thema zu sensibilisieren und dem Einzelnen zu erlauben, sich eine informierte Meinung zu bilden. Anstatt Google aber pauschal „den Kampf anzusagen“, wäre es möglicherweise eine sinnvollere Verwendung derselben Ressourcen seitens der Gemeinden, einen Rundbrief an alle Haushalte zu schicken, der sachlich auf die anstehende Aufzeichnung der Umgebung sowie die Möglichkeit des Widerspruchs gegen die Aufnahme des eigenen Grundstücks hinweist und in einer bebilderten Anleitung erklärt, wie dieser durchgeführt werden kann.

Die zur Meinungsbildung nötigen ungefärbten Informationen über die Tatsachen sind es nämlich, woran es meist am deutlichsten mangelt. Das ist in diesem Fall leider nicht anders.

Das Metaobjektsystem von ECMAScript Harmony und das CLOS-MOP: ein Vergleich

JavaScript ist eine interessante Sprache. Sie hat sich jahrelang mit ihrem Ruf als das häßliche kleine Browser-Scripting-Ding zufriedengegeben, mit dem man sich als Webentwickler eben herumschlagen muß. Seit relativ kurzer Zeit wandelt sich jedoch sowohl das Selbstverständnis der JavaScript-Kultur als auch die Sprache selbst. JavaScript wird nicht mehr nur verwendet, sondern von einigen noch Wenigen auch geliebt. Es entwickelt sich langsam eine Gefolgschaft wie sie bei Python, Ruby und Lisp existiert und die die weitere Entwicklung der Sprache lenkt.

Sie ist es, die versucht, JavaScript aus einer Skriptsprache für Webbrowser in eine auch anderweitig eingesetzte Sprache zu verwandeln. Solche Dinge wie ein (mit den bisherigen Konzepten integriertes) Klassensystem und bessere Unterstützung für lexikalische Variablenbindung und Metaprogrammierung soll die Sprache mit ECMAScript Harmony bekommen.

Das für ECMAScript Harmony vorgeschlagene Metaobjektprotokoll erscheint dabei zunächst einmal unspektakulär. Sicher, es wird möglich sein, Zugriffe auf Attribute abzufangen. Man kann Aufzählungen mit for in umprogrammieren. Man kann Funktionen simulieren. Das sind aber allesamt Dinge, die auch zum Beispiel in Python leicht sind.

Es gibt allerdings einen kleinen, feinen Unterschied zu dem, was Python mit den Unterstrich-Methoden bietet*: Die Objekte (in diesem Kontext Proxies genannt), deren Verhalten umprogrammiert wird, tun das nicht selbst. Stattdessen ist dafür ein sogenanntes Handler-Objekt zuständig. Auf alles, was mit dem Proxy passiert, kann das Handler-Objekt reagieren. Attributszugriffe, -veränderungen und -löschungen, Aufzählungen, das Ändern von Eigenschaften von Attributen, Methodenaufrufe — das Verhalten des Proxys wird vollständig durch das Handler-Objekt implementiert.

Das ist kein unbekanntes Konzept: Es ist das Konzept des Metaobjekts. Grundsätzlich ist ein Metaobjekt ein Objekt, das das Verhalten anderer Objekte beschreibt. (Dabei wird es natürlich seinerseits unter Umständen von einem Metaobjekt beschrieben, welches auch es selbst sein kann.) Offenbar ist ein Handler-Objekt genau das. Sehen wir uns das API einmal an: Es gibt im vorgeschlagenen Metaobjektprotokoll die Methode get, die für jeden Attributslesezugriff aufgerufen wird und das Ergebnis berechnet. Das erinnert sehr an — richtig — AMOP, das de-facto-Standardmetaobjektprotokoll für Common Lisp, nämlich konkret an dessen Methode slot-value-using-class: Genau wie get in JavaScript ist slot-value-using-class nicht polymorph im konkreten Ziel-, sondern dessen Metaobjekt (in diesem Fall der Klasse). Gleiches gilt für alle anderen Methoden im Harmony-Metaobjektprotokoll.

Entsprechung von AMOP- mit JavaScript-Handler-Methoden für den Attributzugriff
delete slot-makunbound-using-class
get slot-value-using-class, compute-effective-method
set (setf slot-value-using-class)
has slot-boundp-using-class

Natürlich bricht die Analogie spätestens an dem Punkt zusammen, an dem es einerseits in Common Lisp um Klassen und generic functions geht, die es in JavaScript nicht gibt — und andererseits bei der generischen Aufzählung von Containerobjekten, die Common Lisp nicht bietet. Dennoch: Die Nähe ist vorhanden, und, jedenfalls gefühlt, gegenüber Lisp stärker als gegenüber Python, Ruby oder gar Java.

Eine Einführung in das Metaobjektsystem von JavaScript (welche möglicherweise auch hilft, die Ideen hinter AMOP zu verstehen) gibt der Vortrag „Changes to ECMAScript, Part 2: Harmony Highlights — Proxies and Traits“ von Tom Van Cutsem.


(*) Mit Deskriptoren gehen — zumindest für Objekte, die nicht selbst Klassen sind — ähnliche Dinge. Attributszugriffe folgen in Python grundsätzlich recht komplizierten Regeln, und philosophisch finde ich die Entfernung zu JavaScripts Proxy-Objekten ziemlich fühlbar.

Eduroam/802.1X mit dem Palm Pre (speziell LMU/TU/LRZ München)

Nicht nur in Deutschland ist es an Universitäten üblich, WLAN-Zugriff via Eduroam anzubieten. Da die Verbindung dabei auf Standards aufbaut und die Konfiguration eines VPN-Clients oder ähnlichem wegfällt, ist das prinzipiell eine sehr schöne Lösung. Leider machen unterschiedliche Rechner dann doch hin und wieder Anstalten, den Eduroam-Verbindungsaufbau zu verstehen.

Nun sollte man annehmen, daß ein so modernes, zudem noch Linux-basiertes Gerät wie der Palm Pre in der Lage ist, einen schnöden WLAN-Verbindungsaufbau problemlos zu meistern. Tatsächlich fragt das Gerät beim Versuch, sich einzuloggen, nach Benutzernamen und Paßwort, doch der naive Ansatz, es wie am PC auch mit der Campus-Kennung der LMU München zu versuchen, schlägt eigenartigerweise fehl.

Die Lösung ist, wie es nach einigem Herumprobieren scheint, sich an der Konfigurationsanleitung für Nokia-Handys zu orientieren. Aus dieser erfährt man, daß der korrekte Benutzername von der Form LRZ-Kennung@ads.mwn.de ist.

Die eigene LRZ-Kennung, die man als Mitglied des LRZs zugewiesen bekommen hat, kann man (als LMU-Student) notfalls über das LRZ-Helpdesk erfragen, Studenten und Mitarbeiter externer Hochschulen können unter Umständen eine Gastkennung beantragen. In der Regel handelt es sich dabei um eine mehr oder weniger zufällig anmutende Ziffern- und Buchstabenfolge.

Das geforderte Kennwort ist das LRZ-Kennwort — bei LMU-Studenten in der Regel identisch mit dem Campus-Kennwort.

Der Grund dafür, daß mit der Campus-Kennung der Login nicht klappt, ist mir nicht bekannt. Möglich auch, daß lediglich die meinige zu lang ist.

Multiple Dispatch in JavaScript (ECMAScript 5)

Folgender Code implementiert Mehrfachdispatch in JavaScript (ECMAScript 5, um genau zu sein). Ich habe ihn unter die MIT-Lizenz gestellt, und er kann als mulkiple-dispatch.js heruntergeladen werden.

Implementierung

"use strict";

function MulkipleDispatchObject(prototype, slots) {
  var inheritsFrom = function(object, other) {
    return (object !== null
            && (object === other
                || inheritsFrom(Object.getPrototypeOf(object), other)));
  };

  var realSlots = {};
  for (var slot in slots) {
    if (!(slots[slot] instanceof Array)) {
      realSlots[slot] = slots[slot];
    } else {
      (function(slot) {
         var mulkiSlot = { method: true, value: function() {
           for (var alternative in slots[slot]) {
             var applies = true;
             alternative = slots[slot][alternative];
             var typelist = alternative['dispatch'];
             for (var i = 0; i in typelist && i in arguments; i++) {
               if (!(arguments[i] === null
                     || arguments[i] instanceof typelist[i]
                     || inheritsFrom(arguments[i], typelist[i]))) {
                 applies = false;
                 break;
               }
             }
             if (applies) {
               return alternative['value'].apply(this, arguments);
             }
           }
           return Object.getPrototypeOf(this)[slot].apply(this, arguments);
         }};
         realSlots[slot] = mulkiSlot;
      })(slot);
    }
  }
  return Object.create(prototype, realSlots);
}
MulkipleDispatchObject.create = MulkipleDispatchObject;

Beispiel

Verwendet wird der Code zum Beispiel wie folgt (hier mit dem printf-Modul von Narwhal):

var printf = require('printf');

// ----- Konstruktoren -----
function Being(name) {
  return MulkipleDispatchObject.create(Being.prototype, {
    name: { value: name, enumerable: true },
    toString: { method: true, value: function() {
      return printf.sprintf("%s", this.name);
    }},
    greet: [{ dispatch: [], value: function(other) {
      printf.printf("%s grüßt %s.", this, other);
    }}]
  });
}

function Person(name) {
  return MulkipleDispatchObject.create(Person.prototype, {
    name: { value: name, enumerable: true },
    greet: [
      { dispatch: [Person], value: function(other) {
          printf.printf("%s sagt: \"Mulk, %s\".", this, other.name);
        }},
      { dispatch: [Cat], value: function(other) {
          printf.printf("%s streichelt %s.", this, other);
        }}]
  });
}
Person.prototype = Being(null, null);
Person.prototype.constructor = Person;

function Cat(name, owner) {
  return MulkipleDispatchObject.create(Cat.prototype, {
    name: { value: name, enumerable: true },
    owner: { value: owner, enumerable: true, modifiable: true },
    greet: [{ dispatch: [], value: function(other) {
      printf.printf("%s miaut %s an.", this, other);
    }}]
  });
}
Cat.prototype = Being(null, null);
Cat.prototype.constructor = Cat;


// ----- Hauptprogramm -----
var matthias = Person("Matthias");
var simon = Person("Simon");
var magdalena = Person("Magdalena");
var mauzi = Cat("Mauzi", magdalena);

matthias.greet(magdalena);  // => Matthias sagt: "Mulk, Magdalena".
magdalena.greet(matthias);  // => Magdalena sagt: "Mulk, Matthias".
simon.greet(matthias);      // => Simon sagt: "Mulk, Matthias".
matthias.greet(simon);      // => Matthias sagt: "Mulk, Simon".
mauzi.greet(matthias);      // => Mauzi miaut Matthias an.
matthias.greet(mauzi);      // => Matthias streichelt Mauzi.

Anmerkungen

Die Implementierung ist sehr naiv, und entsprechend unterwältigend wird vermutlich die Performance sein. Es gibt momentan außerdem keine Möglichkeit, nachträglich Mehrfachmethoden hinzuzufügen.

Äquivalenz von Daten und Code — in Lisp und anderswo

Viele Dinge zeichnen Lisp aus (das Objektsystem, das Makrosystem, die interaktive Entwicklungsweise, das condition system etc.), aber eines, das besonders häufig genannt wird, ist die Äquivalenz von Daten und Code.

Nun sind Daten und Code in Lisp in der Tat gewissermaßen „äquivalenter“ als in anderen Sprachen. Das Wort Äquivalenz klingt aber, als würde es etwas Absolutes bezeichnen. Das ist unglücklich, denn es gibt dabei wie bei den meisten Aspekten aller Dinge in dieser Welt durchaus Abstufungen und verschiedene Ausprägungen. Um das zu durchschauen, muß man aber erst einmal verstehen, worin diese sogenannte Äquivalenz von Code und Daten eigentlich besteht.

Daten sind Code!

Zunächst kann man feststellen, daß Lispcode quasi in einem mit XML vergleichbaren (aber besser für Code geeigneten) Format geschrieben wird. S-Expressions (zu deutsch: symbolische Ausdrücke) kann man sowohl für die Darstellung von Daten als auch von Code sehr gut verwenden. Da das in Lisp auch getan wird, kann Code wie ein Datensatz behandelt werden. Makros machen sich das zunutze, um Code zur Kompilierzeit zu transformieren (Stichwort: statische Metaprogrammierung).

Doch ziehen wir es einmal von der anderen Seite auf. Angenommen, wir wollten eine Klassenhierarchie (also Daten) beschreiben. In XML könnte man die Definition einer Klasse person wie folgt angeben:

<class name="person" superclass="creature">
  <property name="name" accessor="person-name" initarg="name" initform="Mary Unnamed"/>
  <property name="birthday" accessor="person-birthday" initarg="birthday"/>
</class>

Wir können das direkt in S-Expressions übersetzen:

(class :name "person" :superclass "creature"
  (property :name "name" :accessor person-name :initarg :name :initform "Mary Unnamed")
  (property :name "birthday" :accessor person-birthday :initarg :birthday))

Wenn wir die Konventionen ein bißchen weg von XML hin zu Lisp anpassen, ist es ebenso natürlich, stattdessen folgendes zu schreiben:

(defclass person (creature)
  ((name :accessor person-name :initarg :name :initform "Mary Unnamed")
   (birthday :accessor person-birthday :initarg :birthday)))

Hier ist jedoch etwas interessantes geschehen: Der vorangehende S-Ausdruck beschreibt nicht mehr nur Daten. Vielmehr handelt es sich um ausführbaren Code. (Man überzeuge sich selbst davon, indem man ihn in eine Common-Lisp-Implementierung eingibt.)

In anderen Worten: Die „Äquivalenz“ von Code und Daten in Lisp beschränkt sich gerade nicht auf die lediglich oberflächliche Gleichheit der verwendeten Datenstrukturen. (Tatsächlich wird der Stellenwert von Listen als Datenstrukturen in Lispprogrammen weithin überschätzt.) Vielmehr verschwimmt die Grenze zwischen Daten und Code auf eine ganz konkrete Art und Weise, nämlich indem die Daten, die wir schreiben, zugleich als Code dienen.

Einerseits könnte man die fehlende Trennung von Daten und Code als Schlampigkeit werten. Tatsächlich wird ja häufig davor gewarnt, zu viel zu „hardcoden“. Natürlich gilt das für Lispcode genauso, aber die Frage, was eigentlich unter „Hardcoden“ fällt und was nicht, ist nicht so einfach wie in einer Sprache wie C++. Schließlich können solche Dinge wie Klassendefinitionen in Lisp ganz einfach im laufenden Betrieb neu geladen werden, wonach jede Instanz der Klasse die neue Klassenstruktur automatisch übernimmt — ganz so also, als handelte es sich „nur“ um Daten, die man mal eben neu einliest.

In der Praxis: Eingebettete Daten...

Interessant wird es aber spätestens dann, wenn man sich nicht sicher ist, ob etwas, das man definieren will, eher als Daten oder als Code dargestellt werden soll. Stellen wir uns ein Computerspiel mit verschiedenen Monstertypen vor. Wie modellieren wir die Monster? Bekommt jeder Monstertyp eine Klasse auf der Programmebene, oder schreiben wir eine gemeinsame Klasse Monster für alle Monstertypen und lesen die Monsterdaten dann aus Dateien ein? Falls wir den datengetriebenen Ansatz wählen: Was tun wir, wenn wir das Verhalten von Monstern je nach Klasse anpassen wollen? Betten wir eine Skriptsprache in die Datendefinitionen ein oder hardcoden wir die Verknüpfung zwischen Klasse und Verhalten dann doch wieder direkt? Aber inwiefern handelt es sich noch um Daten, wenn wir plötzlich eine ganze Programmiersprache eingebettet haben?

Offenbar verschwimmt hier die Grenze zwischen dem, was man als Daten und dem, was man als Teil des Programms betrachten kann. Ein Lispprogrammierer ist da fein heraus: Er bastelt sich ein Makro, sagen wir define-monster-class, und mischt Daten frei mit Code:

(define-monster-class computer-scientist (humanoid)
  (stats (health 30)
         (strength 20)
         (charisma -10)
         (intelligence 90))
  (extra-talents (coffee-tolerance 100) (keyboard-cleaning 40))
  (natural-enemy-reactions (patent-lawyer (enemy)
                             (make-jokes-about enemy)
                             (glare-at enemy))
                           (end-user ()
                             (run-away)))
  (on battle-entry (me enemies)
    (cry "You will be repartitioned!")
    (tell-others
      (protect me)
      (attack enemies))
    (make-awkward-gesture)
    (attack enemies)))

...gibt es nicht nur in Lisp.

So weit, so gut. Aber widmen wir uns anderen Programmiersprachen. Wie nah an Lisp können wir herankommen, um unsere Daten in Code einzubetten? In Ruby bekommt man mit entsprechender Metaprogrammierung folgendes hin:

class ComputerScientist < Humanoid
  stat :health, 30
  stat :strength, 20
  stat :charisma, -10
  stat :intelligence, 90
  extra_talents { :coffee_tolerance => 100, :keyboard_cleaning => 40 }
  on :natural_enemy_encounter, PatentLawyer do |enemy|
    make_jokes_about enemy
    glare_at enemy
  end
  on :natural_enemy_encounter, EndUser do
    run_away
  end
  on :battle_entry do |enemies|
    cry "You will be repartitioned!"
    tell_others { |me|
      protect me
      attack enemies
    }
    make_awkward_gesture
    attack enemies
  end
end

Zugegeben: Es ist insofern ein konstruiertes Beispiel, als es sich hier um etwas handelt, das ein traditionelles Klassensystem gut modellieren kann. Aber ähnliche Techniken kommen zum Beispiel in Ruby on Rails für die Angabe von Datenbankschemata zum Einsatz:

ActiveRecord::Schema.define do
  create_table :articles do |table|
    table.column :id, :integer
    table.column :title, :string
    table.column :author, :string
    table.column :body_text, :string
    table.column :published, :datetime
  end
end

Es ist sicherlich nicht weit hergeholt, zu behaupten, es handle sich bei einem Datenbankschema um Daten, nicht so sehr um Code. Ruby erlaubt es, diese Daten recht natürlich in Code einzubetten. Die Sprache hat eben eine große philosophische Nähe zu Lisp.

Was ist mit anderen Sprachen? In JavaScript könnte man so etwas wie das Folgende relativ leicht umsetzen:

var ComputerScientist = makeMonsterType(Humanoid, {
  stats: {
    health: 30,
    strength: 20,
    charisma: -10,
    intelligence: 90
  },
  extraTalents: { CoffeeTolerance: 100, KeyboardCleaning: 40 },
  naturalEnemies: {
    PatentLawyer: function(enemy) {
                    this.makeJokesAbout(enemy);
                    this.glareAt(enemy);
                  },
    EndUser: function() {
               this.runAway();
             }
  },
  onBattleEntry: function(enemies) {
    this.cry("You will be repartitioned!");
    this.tellOthers(function(me) {
      this.protect(me);
      this.attack(enemies);
    });
    this.makeAwkwardGesture();
    this.attack(enemies);
  }
});

Das ist schon nicht mehr ganz so lispig wie die Ruby-Variante, weil Code und Daten strikter getrennt sind. Außerdem hat man das Problem des Neuladens: Wie sorgt man nach dem Verändern des Codes dafür, daß bestehende ComputerScientists die neuen Attribute bekommen? (Ruby verhält sich diesbezüglich wie Lisp.) Immerhin aber gibt es die passende Notation für Daten sowie starke dynamische Metaprogrammierungsfähigkeiten in der Sprache — damit ist schon einiges machbar.

In Python dagegen sieht es schon wesentlich düsterer aus. Man müßte etwas wie das Folgende schreiben, um noch einigermaßen innerhalb der Konventionen der Sprache zu bleiben (und auch das geht nur deshalb noch relativ gut, weil wir etwas modellieren, das sich gut in Klassen ausdrücken läßt):

class ComputerScientist(Humanoid):
    health = 30
    strength = 20
    charisma = -10
    intelligence = 90
    talents = dict(Humanoid.talents, CoffeeTolerance=100, KeyboardCleaning=40)
    
    def on_battle_entry(self, enemies):
        self.cry("You will be repartitioned!")
        self.tell_others(Creature.protect, self)
        self.tell_others(Creature.attack, enemies)
        self.make_awkward_gesture()
        self.attack(enemies)
    
    @natural_enemy_reaction(PatentLawyer)
    def patent_lawyer_reaction(self, enemy):
        self.make_jokes_about(enemy)
        self.glare_at(enemy)
    
    @natural_enemy_reaction(EndUser)
    def end_user_reaction(self, enemy):
        self.run_away()

Zugegeben: Es könnte schlimmer sein. Dennoch weicht der Code schon stärker von dem ab, was man intuitiv schreiben würde, um die Daten zu beschreiben — ganz zu schweigen davon, daß man mit Python (im Gegensatz zu Ruby!) dieselben Probleme wie mit JavaScript hat, was das Neuladen der Klassendefinition angeht.

In Sprachen wie Java oder C++, deren Metaprogrammierungsfähigkeiten wesentlich geringer sind, geht das Ganze natürlich erst recht nur mit argen Verrenkungen (wie z.B. externen Codegeneratoren und fragwürdigen Linker-Tricks), so daß stattdessen dann meist eine Skriptsprache eingebettet und jede Form von Vermischung von Daten und Code als Hardcoding geächtet wird.

Conclusio

Das Verschwimmenlassen von Code mit Daten ist keine simple Ja/Nein-Frage. Natürlich macht auch die oberflächlichere strukturelle Äquivalenz von Daten und Code in Lisp es einem leichter, die entsprechende de-facto-Äquivalenz herzustellen und auszunutzen. Und doch gibt es sie in verschiedenen Ausprägungen in unterschiedlichen Programmiersprachen und Kontexten. Letztlich ist sie nichts weiter als eine Form von Deklarativität, in der der Programmierer die deklarativen Elemente zu einem gewissen Grad selbst definiert.

Man darf bei alledem aber nicht vergessen, daß die Praktikabilität eines Paradigmas in einer gegebenen Programmiersprache auch stets eine kulturelle Frage ist. Wie realistisch es ist, Metaprogrammierung und in die Sprache eingebettete anwendungsspezifische Subsprachen zu verwenden, hängt schließlich nicht zuletzt damit zusammen, wie gut es von den verfügbaren Entwicklungswerkzeugen und Bibliotheken unterstützt wird.

Ältere Einträge

Alle Einträge vollständig anzeigen (langsam!).

Einträge nach Datum
TitelDatumKommentare
Google Street View vs. Gemeinden15.8.2010, 11:090 Kommentare
Das Metaobjektsystem von ECMAScript Harmony und das CLOS-MOP: ein Vergleich30.7.2010, 21:130 Kommentare
Eduroam/802.1X mit dem Palm Pre (speziell LMU/TU/LRZ München)14.7.2010, 18:010 Kommentare
Multiple Dispatch in JavaScript (ECMAScript 5)3.6.2010, 12:060 Kommentare
Äquivalenz von Daten und Code — in Lisp und anderswo18.5.2010, 17:260 Kommentare
Ein Tool-Wrapper als Programmiersprachentest30.3.2010, 14:380 Kommentare
Die Dualität zwischen Conditions und dynamischen Variablen26.3.2010, 17:101 Kommentar
Pre-Scheme und Freunde: doch noch richtiges Low-Level-Lisp16.2.2010, 9:420 Kommentare
Low-Level-Lisp15.2.2010, 21:002 Kommentare
Das bayerische Studentenwerk wird ab sofort kaputtgespart30.1.2010, 8:441 Kommentar
„Aber was ist mit denen, die sich dann einfach durchfüttern lassen?“ — Eine Verteidigung des Rechts auf Faulheit23.1.2010, 16:173 Kommentare
Ein Rat für Android-Freunde: Wartet auf das Nexus One.19.1.2010, 17:270 Kommentare
Chaosradio Express zu: Mut zur Freiheit18.1.2010, 18:150 Kommentare
Eindrücke vom Notizenprogramm Circus Ponies NoteBook17.1.2010, 14:500 Kommentare
myBlogEdit — ein einfacher Desktop-Blogging-Client, der seine Arbeit tut17.1.2010, 13:120 Kommentare
Die Welt der freien Software vor dem Scheideweg14.1.2010, 15:251 Kommentar
Syntaxhervorhebung von Lisp-Code im Web7.12.2009, 22:560 Kommentare
Stilistische Unterschiede zwischen Clojure und Common Lisp anhand von HTML-Generierung3.12.2009, 12:500 Kommentare
Backups auf einen Dateiserver17.10.2009, 23:240 Kommentare
ecto — Sinn und Unsinn eines Desktop-Blogging-Clients9.10.2009, 15:320 Kommentare
Implementierung eines Atom-basierten Webdienstes8.10.2009, 22:270 Kommentare
Deutsche Kleinparteien: Ökologisch-Demokratische Partei23.9.2009, 0:190 Kommentare
Deutsche Kleinparteien: Liberale Demokraten21.9.2009, 8:251 Kommentar
Serie: Deutsche Kleinparteien21.9.2009, 7:512 Kommentare
Befehls- als partielle Metataste in iTerm11.8.2009, 22:392 Kommentare
Lisp im Chaosradio Express10.8.2009, 21:392 Kommentare
Transfinite Wahrscheinlichkeitslogik online10.8.2009, 13:182 Kommentare
Monaden in Scala31.7.2009, 15:411 Kommentar
Bearbeiten von Tabellen in Numbers mit AppleScript18.7.2009, 22:370 Kommentare
Ad-hoc-Polymorphie in Scala: besser als Haskell?25.6.2009, 19:080 Kommentare
Funktionale Programmierung ist algebraische Programmierung21.6.2009, 14:071 Kommentar
Scala21.6.2009, 14:070 Kommentare
Entwurf einer auf natürliche Weise homoikonischen objektbasierten Sprache30.5.2009, 22:120 Kommentare
.tar.bz2/.tar.gz in .lzma.io (cpio/afio) umwandeln28.3.2009, 17:594 Kommentare
Interaktive GUI-Programmierung mit SLIME, Clojure, Qt und Swing11.3.2009, 12:072 Kommentare
Lektionen aus dem Erfolg von Clojure und dessen Bedeutung für Lisp20.2.2009, 14:392 Kommentare
Öffentliche Petition zum bedingungslosen Grundeinkommen17.2.2009, 17:410 Kommentare
Freitag31.1.2009, 19:400 Kommentare
Kryptofaschistische Blut- und Bodenideologie des Sportfanatismus11.1.2009, 16:540 Kommentare
Inkscape5.1.2009, 13:230 Kommentare
Dovecot, launchd und die Leopard-Firewall4.1.2009, 13:190 Kommentare
F-Spot und ipernity31.12.2008, 17:240 Kommentare
Diskret-topologische Wahrscheinlichkeitslogik und die transfinite Behandlung endlicher Gruppen20.12.2008, 23:005 Kommentare
Wörter zählen mit Common Lisp16.12.2008, 14:592 Kommentare
Genossenschaften vs. öffentliche vs. Privatunternehmen15.12.2008, 20:021 Kommentar
Feministische Doppelmoral15.11.2008, 15:130 Kommentare
Dresden for the win!15.11.2008, 14:410 Kommentare
Verschiedene Beweisstrategien in der Mathematik und ihre Anwendungen12.11.2008, 21:360 Kommentare
Die universelle Eigenschaft der Klumpentopologie1.11.2008, 19:570 Kommentare
Ein weiterer Klassiker18.10.2008, 14:270 Kommentare
Vorträge über Clojure18.10.2008, 13:130 Kommentare
Backquote in Clojure und die Referenztransparenz14.10.2008, 18:340 Kommentare
Clojure12.10.2008, 15:040 Kommentare
Das deprimierende Thema der Familienpolitik24.9.2008, 19:230 Kommentare
SOLID, ein SLIME für O'Caml6.9.2008, 16:460 Kommentare
Das schöne C-Interface von Objective Caml1.9.2008, 16:260 Kommentare
Survey: Mehrsprachendokumentationsgeneratoren29.8.2008, 19:440 Kommentare
Die Objective-C-Runtime als Compilertarget25.8.2008, 15:360 Kommentare
FIXNUMs für Toilet Lisp4.8.2008, 16:430 Kommentare
Toilet Lisp: MACROLET als COMPILER-LET-Ersatz3.8.2008, 20:070 Kommentare
OpenJDK und libmawt.so22.7.2008, 13:470 Kommentare
Adé, Bill2.7.2008, 18:350 Kommentare
Toilet Lisp: der Code22.6.2008, 17:240 Kommentare
Toilet Lisp22.6.2008, 8:562 Kommentare
Die Avantgarde schlägt zurück21.6.2008, 18:070 Kommentare
Étoilé nähert sich Smalltalk an7.6.2008, 12:420 Kommentare
Systemupdates mit NetBSDs pkgsrc-System31.5.2008, 12:030 Kommentare
Warum ich gegen den Antifaschismus-Vorschlag gestimmt habe27.5.2008, 18:030 Kommentare
Die USA, erklärt21.5.2008, 19:060 Kommentare
Smalltalk als Standardsprache für Étoilé19.5.2008, 19:100 Kommentare
Paketmanagement unter Mac OS X3.5.2008, 19:481 Kommentar
CamlP4 und CamlP529.4.2008, 12:060 Kommentare
Lesbare Syntax für OCaml27.4.2008, 15:310 Kommentare
Ad-hoc-Polymorphie: Gut? Schlecht? Keines von beiden?23.4.2008, 13:070 Kommentare
Leseprobe: Der gebrauchte Mann19.4.2008, 11:560 Kommentare
Qualität in der Wikipedia, continued14.4.2008, 17:110 Kommentare
Pico Lisp, Fenster in eine andere Welt?2.4.2008, 10:070 Kommentare
Lisp-Einführung1.4.2008, 18:141 Kommentar
Objective-CL 0.2.05.3.2008, 21:170 Kommentare
SpamAssassin-Migration zwischen Rechnern30.12.2007, 20:240 Kommentare
Eine Projektseite für Objective-CL24.12.2007, 14:230 Kommentare
Formulierungsspießertum9.12.2007, 14:470 Kommentare
GNUstep: Menüleistenstile25.11.2007, 14:460 Kommentare
Gezwungen, Subversion zu verwenden? git-svn bringt den Spaß zurück.24.11.2007, 13:100 Kommentare
Wer sind die Alt-Katholiken?5.11.2007, 22:140 Kommentare
Perl-Einzeiler für Multiline-Regexps4.11.2007, 20:340 Kommentare
Gedenkt unser jemand?3.11.2007, 18:300 Kommentare
Qualität? In der Wikipedia? Auf welchem Planeten leben Sie?3.11.2007, 17:090 Kommentare
CL-ObjC — freundliche Konkurrenz zu Objective-CL1.11.2007, 21:406 Kommentare
Mit kleinen Schritten in die Utopie — sozial wie ökologisch15.10.2007, 16:060 Kommentare
Denkwürdige Merkmale der Sprache C: #import versus #include14.10.2007, 11:220 Kommentare
Denkwürdige Merkmale der Sprache C: dynamische Speicherreservierung einmal anders11.10.2007, 17:202 Kommentare
Denkwürdige Merkmale der Sprache C: getc liefert keinen char zurück11.10.2007, 17:000 Kommentare
Kampf dem Spam!7.10.2007, 17:120 Kommentare
Objective-CL, eine Objective-C-Brücke für Common Lisp25.9.2007, 22:580 Kommentare
Mulkutils: Version 0.2.013.7.2007, 14:160 Kommentare
Optimierungsflags für den Intel Core Duo11.7.2007, 18:540 Kommentare
DellfanD für Solaris28.6.2007, 13:530 Kommentare
Mulkutils: kleine Werkzeuge für Common Lisp28.6.2007, 13:180 Kommentare
MAPCAN, ein kleines Juwel10.6.2007, 15:430 Kommentare
Zurück aus der Dunkelheit30.5.2007, 19:461 Kommentar