Zurzeit überlege ich hin und wieder, wie eine Programmiersprache aussehen könnte, die einerseits objektbasiert ist und andererseits auf so offensichtliche Weise selbstdarstellend wie Lisp. Mein Ziel ist eine Sprache, die gut in einen vornehmlich oder rein objektorientierten Kontext paßt und von derselben Flexibilität profitiert, die Lisp durch Makros erhält.

Momentan hinkt mein Sprachdesign noch. Einige Stellen müssen von haarsträubenden inneren Widersprüchen bereinigt werden. Im großen und ganzen scheint mir das Konzept aber durchführbar zu sein -- die Praktikabilität muß sich letzten Endes jedoch natürlich in einem Praxistest herausstellen.

Als kleinen Vorgeschmack stelle ich hier kurz den derzeitigen Entwurf vor. Man bedenke, daß der Entwurf einer von vielen ist, die größtenteils bereits ihren Weg in den Papierkorb gefunden haben, und es nicht ganz und gar unwahrscheinlich ist, daß ihm selbst dasselbe Schicksal widerfahren wird. Man wird sehen.

Idee

Die grobe Idee ist es, eine prototypenbasierte, objektorientierte Sprache mit einer möglichst regulären Syntax zu basteln, welche auf Nachrichtensendungen, d.h. auf Methodenaufrufen basiert. Im Prinzip ähnelt die Sprache der Sprache Self, außer daß die Syntax regulärer ist und Blöcke durch Makros ausgedrückt werden.

Syntax

Im Gegensatz zu den meisten anderen Sprachen ist in meinem Sprachentwurf die abstrakte Syntax von entscheidender Bedeutung. Die Sprache kennt vier Arten von zusammengesetzten Konstrukten:

  1. Sequenzen: a. b. c.

  2. n-tupel: a : b : c

  3. Listen: a, b, c

  4. Vektoren: a b c

Der Operatorvorrang geht hierbei von unten nach oben, d.h. a: b, c. d: e. bezeichnet eine Sequenz von zwei 2-tupeln (Paaren), von denen das erste als zweite Komponente eine Liste aus zwei Elementen enthält.

Semantik

Interpretiert wird das Ganze so:

  1. Ein Programm ist eine Sequenz von Anweisungen.
  2. Eine Anweisung ist ein n-tupel oder ein Literal.
  3. Wie genau ein gegebenes Anweisungstupel interpretiert wird, hängt vom ersten Element ab.
    1. Ist dieses ein Makroname oder ein Vektor, der als zweite Komponente einen Makronamen enthält, dann wird das Makro aufgerufen und das Ergebnis erneut betrachtet.
    2. Anderenfalls gelten folgende Regeln: Ein Tupel der Form a b: c, d, e, f wird als Aufruf der Methode b auf dem Objekt a interpretiert. c bis f bezeichnen die Argumente des Methodenaufrufs. Diese dürfen wiederum Anweisungen sein (allerdings muß häufig geklammert werden, wie man leicht an einem beliebigen hinreichend komplexen Beispiel sehen kann). Es müssen auch keine Argumente da sein, und in diesem Fall kann man auch den Doppelpunkt weglassen, d.h. der ganze Ausdruck ist dann gar kein Tupel sondern eigentlich ein Vektor. Fehlt a (die erste Komponente des Tupels ist dann kein Vektor), so wird implizit self als Empfänger der Nachricht angenommen. (Dem geneigten Leser wird auffallen, daß self selbst auch lediglich eine Nachrichtensendung an self ist, d.h. self ist äquivalent zu self self, dieses wiederum zu (self self) self usw.. Das erscheint etwas zirkulär, wird aber vom Compiler einfach abgekürzt.)
  4. Ein Literal ist ein Numeral (z.B. 9.5 oder -42), ein String oder ein zusammengesetztes Konstrukt mit geschweiften Klammern außen herum, z.B. {x: 10. y: 20.} oder {(1 + 3) print.}. Literale werden direkt als solche in den Code übernommen und ihr Inhalt wird nicht selbst als Code interpretiert, es sei denn ein Makro transformiert sie entsprechend.

Makros

Makros transformieren ihren Aufruf zur Kompilierzeit in eine beliebige andere Anweisung. Es sind noch einige Fragen offen im Hinblick auf das Problem, zwischen Makro- und Methodenaufrufen zu unterscheiden. Besonders die Interaktionen mit einem etwaigen Modulsystem bereiten mir noch Kopfzerbrechen.

Beispielprogramme

Fibonacci-Zahlen (einfach)

Ein einfaches Beispielprogramm, das die zehnte Fibonaccizahl berechnet und ausgibt, sähe vielleicht wie folgt aus:

Integer defMethod: fib {  
 
  (< 2) if: {  
 
    self.  
 
  }, {  
 
    ((self - 1) fib) + ((self - 2) fib).  
 
  }.  
 
}.  
 
 
 
"Die zehnte Fibonaccizahl ist " print.  
 
(10 fib) printLn.  
 

Fibonacci-Zahlen (Dispatch-basiert)

Obiges Programm könnte man auch wie folgt formulieren:

0 defMethod: fib { 0. }.  
 
1 defMethod: fib { 1. }.  
 
Integer defMethod: fib { ((self - 1) fib) + ((self - 2) fib). }.  
 
 
 
"Die zehnte Fibonaccizahl ist " print.  
 
(10 fib) printLn.