Io ist eine nette kleine Sprache, war die letzten Jahre aber doch sehr im Fluss. Und ob man die Einfachheit nun wirklich nur an der Anzahl der Schlüsselworte zählen kann?
Bei Smalltalk und Io gibt es wie bei Scheme das Streben nach einer uniformen Syntax. Insbesondere lassen sich dadurch Kontrollstrukturen (Schleifen, bedingte Anweisungen) in der Sprache ausdrücken und auch erweitern. Das ist ein mächtiges Feature, doch es macht die Sprache nicht unbedingt einfacher. Die (operationelle) Semantik von Io lässt sich nicht so einfach beschreiben, man muss sie aber kennen, um das Programm zu verstehen. Ich finde sie - aber das ist wahrscheinlich Gewohnheit, bei Smalltalk und Scheme einfacher.
Am einfachsten ist vielleicht Scheme: Ein Atom ist ein Ausdruck ohne Klammern, z.B. eine Zahl, ein String oder ein Symbol. Bis auf Symbole, die als Variablen aufgefasst werden und durch durch den an sie gebundenen Wert ersetzt werden, sind die anderen Atome direkt Werte. In Listen der Art (e0 e1 e2 ... eN) werden die Unterausdrücke e0 bis eN rekursiv ausgewertet. Das Ergebnis von e0 muss ein Funktionswert sein, der dann mit den anderen Werten als Argumente aufgerufen wird.
Ausnahme für diese Regel sind bestimmte Symbole für e0, etwa "if" oder "quote" oder "lambda". Hier passiert trotz gleicher Syntax wie bei einem Funktionsaufruf etwa anderes.
Außerdem muss man bei Scheme noch wissen, wie die Gültigkeitsbereiche von Variablen sind und dass Endrekursion den Stack nicht wachsen lässt, damit man Schleifen mittels rekursiver Funktionen effizient implementieren kann. Das war's dann aber auch schon.
Bei Smalltalk ist es ähnlich. Es gibt Literale (Zahlen, Strings, Symbole), die zu sich selbst ausgewertet werden. Es gibt drei Arten von Nachrichtenausdrücken, unäre, wo dem Objekt ein Nachrichtenname ohne Argument folgt, binäre, wo dem Namen ein Argument folgt und Schlüsselwortnachrichten, wo sich der Name der Nachricht aus Schlüsselworten zusammensetzt, denen jeweils ein Argument folgt.
Das Prinzip ist immer Objekt-Nachricht. Alles ist ein Objekt und versteht Nachrichten, weil jedes Objekt ein Exemplar einer Klasse ist (auch Klassen sind Objekte, nämlich Exemplare von Metaklassen) und Nachrichten lösen die Ausführung von über die Klassenhierarchie zu suchenden und bei den Klassen gespeichertern Methoden aus. Ergebnis ist immer ein Objekt. Ein "super send" ist noch etwas spezieller als die normale Methodensuche, aber wenn man diese beiden Konzepte, Zuweisungen mittels ":=" und "^" als return-Anweisung verstanden hat, kennt man alles.
In Smalltalk muss man nicht lernen, dass "if" wie in Scheme etwas besonderes ist, sondern Kontrollstrukturen werden (jedenfalls augenscheinlich - die Maschine optimiert das in der Regel) direkt in Smalltalk realisiert:
Dem Objekt in der Variable "a" (sagen wir, eine 5) wird die binäre Nachricht "<" mit dem Argument 10 geschickt. Ergebnis ist das Objekt true (Exemplar der Klasse True) oder false (Exemplar der Klasse False) - in meinem Fall natürlich true - und dem Objekt wird die Nachricht ifTrue:ifFalse: (ja, das ist eine Nachricht!) mit zwei Codeblöcken als Argumente geschickt. Hier sind die Definitionen:
Code: Alles auswählen
True ifTrue: aBlock ifFalse: anotherBlock
^aBlock value
False ifTrue: aBlock ifFalse: anotherBlock
^anotherBlock value
Auch der Block in [...] ist ein Objekt und versteht die Nachricht "value", wenn er sich auswerten soll.
Die Syntax von Io versucht noch uniformer zu sein als die von Smalltalk, da es nur eine Art von Nachrichtenausdruck gibt - ganz traditionell folgt dem Namen die Liste der Argumente in Klammern. Ohne Argumente kann man die Klammern auch weglassen. Außerdem sind auch Zuweisungen Nachrichten, ein Konzept, was Smalltalk wieder fallen gelassen hat.
Im Gegensatz zu Scheme, wo ("call by value") alle Argumente ausgewertet werden, bevor eine Funktion aufgerufen wird, funktioniert Io hier anders: Nur die ersten N Ausdrücke an Argument-Position werden ausgewertet, beim Rest wird ("call by name") die Nachricht selbst übergeben. Im Prinzip hat man dadurch wieder die Special-Forms von Scheme, kann sie aber meist in Io definieren, weil man über die pseudo-Variable "call" immer an den aktuellen Kontext herankommt (Smalltalk nennt dies "thisContext", eine Pseudovariable, die man dort fast nie braucht und die auch nicht alle Smalltalk-Dialekte zur Verfügung stellen). Die "=" und ":=" werden zudem als Makros aufgefasst und e1 symbol := e2 wird durch e1 setSlot("symbol", e2) und bei "=" durch updateSlot ersetzt. Das e1 kann fehlen, dann wird implizit das aktuelle "locals"-Objekt als Empfänger benutzt. Tatsächlich sagt die Doku, dass auch e symbol als Makro für e getSlot("symbol") aufzufassen ist, aber da beißt sich die Katze in den Schwanz, denn bitte was ist dann "e getSlot"?
Ich glaube, so könnte man das if von Io nachbauen (ist der selbe Trick wie bei Smalltalk, nur das ich ein spezielles "SkipFalse"-Objekt benutze statt einer einzelnen ifTrueIfFalse-Methode):
Code: Alles auswählen
if(a < 10, stmt1..., stmt2...)
if := method(cond,
cond ifTrue(call evalArgAt(1)) ifFalse(call evalArgAt(2))
)
true ifTrue := method(SkipFalse clone value := call evalArgAt(0))
true ifFalse := method(false)
false ifFalse := method(call evalArg(0))
SkipFalse = object clone
SkipFalse ifFalse := method(self value)
Jetzt habe ich mich aber um eine Antwort gedrückt, warum Python nicht wirklich objektorientiert ist. Ich glaube, ich war zu pauschal in meiner Aussage. Man kann mit Python objektorientiert programmieren, doch Python ist vom Kern eine imperative Programmiersprache mit Anleihen aus der objektorientierten und funktionalen Programmierung. Vielleicht macht das den Erfolg aus (ich glaube ja, Multiparadigmen-Sprachen sind die mächtigsten, allerdings braucht es Entwickler die alle diese Paradigmen kennen) aber Python folgt nicht konsequent dieser Idee. Das print-Statement ist kein Objekt. Klassen wirken nachträglich aufgesetzt und die Implementierung von Methoden als Funktionen scheint komplett durch. Daher folgen die wenigsten Python-Programmierer und Python-Programme der ursprünglichen Idee sondern sind ein Konglomerat aus Konzepten. Gut für die Praxis, weniger gut für's Lernen.
Ansonsten hast du Recht, auf unbekannte Nachrichten reagieren zu können ist ein mächtiges Konzept, was nur wenige Sprachen (Ruby kann's übrigens auch) beherrschen. Nachrichten bei Smalltalk sind (im Gegensatz zu Io) übrigens immer synchron. Daher sagte ich ja, Erlang trifft die ursprüngliche Idee fast noch besser...
PS: Es heißt Smalltalk, nicht SmallTalk ;)
Stefan