Passage des messages
Smalltalk utilise le passage de messages, pas l'invocation de méthodes. La distinction est subtile, mais extrêmement puissante.
Un peu de terminologie : Étant donné foo bar: baz
, #bar:
est un sélecteur , foo est le récepteur d'un message appelé #bar:
(le # indique un symbole, un peu comme Common Lisp dirait 'bar
(ou de manière encore plus appropriée, :bar
)), et baz
es un argument o paramètre . Quand la ligne est exécutée, foo
est envoyé le message #:bar:
avec argument baz
. Jusqu'à présent, c'est assez normal. En Java, cela ressemblerait à foo.bar(baz);
.
En Java, le système d'exécution découvrirait foo
Le type réel de l'utilisateur, trouver la méthode la plus appropriée et l'exécuter.
Les choses ont l'air presque la même chose en Smalltalk. Lorsque vous envoyez un message à un objet, celui-ci recherche dans son dictionnaire de méthodes une méthode dont le nom correspond à celui du sélecteur du message. S'il n'en trouve pas, il cherche dans le dictionnaire des méthodes de sa superclasse, et ainsi de suite. C'est plutôt normal.
S'il ne trouve pas de méthode correspondante, il s'envoie à lui-même le message suivant #doesNotUnderstand:
avec le message original comme paramètre. (Oui, un message envoyé est un objet.) Mais #doesNotUnderstand:
n'est également qu'une méthode. Vous pouvez la surcharger.
Par exemple, vous pouvez avoir un objet qui répond à un certain nombre de messages et qui transmet tous les autres messages qu'il reçoit à un objet délégué. Remplacer #doesNotUnderstand:
et hop, vous avez un proxy qui n'aura pas besoin de maintenance pour maintenir son protocole en synchronisation avec le délégué.
Syntaxe triviale
Non, je ne plaisante pas. La grammaire entière de Smalltalk fait peut-être 15 lignes de long. Le JLS ne l'est... pas. Pourquoi s'en soucier ? Une syntaxe simple permet de déchirer facilement un morceau de code. Métaprogrammation ! Refactoring !
Aucune syntaxe pour :
- les déclarations conditionnelles :
(n < 3) ifTrue: ['yes'] ifFalse: ['no']
- pour les boucles :
1 to: 10 do: [:i | Transcript show: i asString]
- try-catch :
[i := i / 0] ifError: ['oops!']
- essayer de terminer :
[i := i / 0] ensure: [stream close]
Et remarquez toutes ces []
s - fermetures de première classe avec une syntaxe propre.