Les bases de la syntaxe Smalltalk

From OFSET Wiki

Jump to: navigation, search

Traduction de The Squeak syntax reference. Autorisation de S. Ducasse, voir ses autres chapitres.

Contents

[edit] Introduction

Dans ce chapitre je souhaite introduire la syntaxe du langage Squeak aux programmeurs d'autres langages. Noter que Squeak est un Smalltalk, donc n'importe quel ouvrage sur Smalltalk peut être utilisé pour avoir un autre point de vue sur la syntaxe et le modèle. Smalltalk fût influencé par les langages LISP (fermeture lexicale, uniformité, bloc de contrôle défini dans le langage lui-même), LOGO (un langage fonctionnel dynamique) et Simula (le paradigme de l'orienté objet)

La syntaxe de Squeak est basée sur (1) 6 identifiants réservés ; (2) des expressions constantes appelées objets littéraux, qui comprennent les nombres, les caractères, les chaînes de caractères, les symboles et les tableaux ; (3) les identifiants et l'affectation ; (4) les messages ; (5) les closures - block closures en anglais - ce sont des fonctions anonymes et des séquences d'expressions à exécution différée. Basée sur ces éléments syntaxiques, les expressions conditionnelles et d'itération sont naturellement définies sans avoir besoin de constructions spécifiques. Smalltalk est un langage typé dynamiquement, et ainsi vous n'avez jamais besoin de préciser le type de la variable passée en argument de méthode.

Certaines parties de ce chapitre sont inspirées du manuel de référence rapide de Squeak, écrit par Andrew C. Greenberg and Andrew P. Black. Je les remercie pour leur travail et pour m'avoir autorisé à le réutiliser. Je vais commencer par donner une vue d'ensemble de la syntaxe et j'avancerai ensuite pas à pas vers les détails. Si vous êtes uniquement intéressés par la syntaxe, vous pouvez sauter la première section, qui commence avec quelques exemples. J'illustrerai l'explication de la syntaxe de quelques petits scripts, et je vous suggère d'essayer toutes les expressions proposées.

[edit] Uniformité et simplicité

Comme vous le découvrirez bientôt, la syntaxe de Smalltalk n'introduit pas d'instructions spécifiques pour les tests, les boucles, les définitions de classes et de méthodes. Ceux-ci sont exprimés en utilisant les éléments syntaxiques de base, c'est-à-dire les messages et les blocs. Ainsi un test est un message envoyé à un booléen (voir section 14), une boucle est un message envoyé à un entier ou à une collection avec le code devant être répété exprimé sous la forme d'un bloc (block closure, voir section 14).

La syntaxe de Smalltalk est simple pour peu de faire l'effort d'oublier les vieux réflexes créés par les autres langages comme C, C++ et Java et d'admettre qu'une alternative plus simple est possible. Vous devez savoir que l'intention originelle des inventeurs de Smalltalk était de développer un langage que les enfants pourraient maîtriser. Aussi, le code ressemble à des phrases en anglais et il peut être lu plus ou moins littéralement.

Ralph Johnson, un des quatre auteur du livre Design Patterns, dit souvent que la syntaxe de Smalltalk peut tenir sur une carte postale comme le montre l'exemple ci-dessous. Bien évidemment, cette méthode ne fait rien de bien utile, mais elle contient tous les éléments syntaxiques de Smalltalk !

Méthode 1

exampleWithNumber: x
"This is a small method that illustrates every aspect of   
the Smalltalk method syntax except primitives, which
aren't very standard. It has unary, binary, and keyword
messages; declares arguments and temporaries (but not
block temporaries); accesses a global variable (but not 
class and instance variables); uses literals (array,
character, symbol, string, integer, float); uses 
the pseudovariables true, false, nil, self, and super, 
and has sequence, assignment, return and cascade. It has 
both zero-argument and one-argument blocks. However, it 
doesn't do anything useful."
  |y|
  true & false not & (nil isNil) ifFalse: [self halt].
  y := self size + super size.
  #($a #a 'a' 1 1.0)
    do: [:each | Transcript
               show: (each class name);
               show: (each printString);
               show: ' '].
  ^x<y

[edit] Éléments syntaxiques

Voici un résumé des éléments syntaxiques de Squeak. Les détails viendront plus tard.

  • $ -- défini un caractère
  • ' ' -- chaîne de caractères. Utiliser deux quotes simples pour représenter l'apostrophe ou une quote simple : 'ici', 'c''est drôle'
  • # -- défini un symbôle (identifiant de type chaîne de caractères unique); #JeSuisUnique
  • #() -- défini un tableau à la compilation. #(a b #(true))
  • {} -- défini un tableau à l'exécution. Ainsi {1+3 . 2*5} défini un tableau avec les éléments 4 et 10
  • <primitive:...> -- défini un appel de primitive dans la machine virtuelle
  • " " -- commentaire: "ceci est un commentaire"
  • Par convention, les variables locales ou privées commencent par une minuscule, et les variables globales par une majuscule. Ainsi les noms de classe commencent aussi par une majuscule car ce sont des variables globales. Ainsi true est une instance de la classe True.
  • | | -- déclare des variables locales dans un contexte, une méthode, un bloc (block-closure)
  •  := -- (et _, qui s'affiche comme une flèche (<- en Squeak), permet d'affectation du contenu d'une variable

Exemple 1

|x y|
x := 3.
y := x + 1.
y
  • self, super, nil, true, false, et thisContext sont des identifiants réservés, aussi appelés pseudo-variables car elles ne peuvent être que lues et sont définies par le système.
  • ^ -- retourne le résultat d'une méthode ou d'un bloc. ^ fonctionne comme un mécanisme d'échappement. Il permet de sortir de la méthode qui le contient même si profondément enfoui dans des blocs ou des tests. Par défaut, toutes les méthodes retournent le receveur (self), mais le navigateur de code ne montre le receveur que si nécessaire.
  • . -- un séparateur d'expression (et non pas un code terminal, aussi il n'est pas nécessaire à la fin d'un script).
  •  ; -- (appelé cascade) permet d'envoyer plusieurs messages au même objet.
  • [ ] -- défini un bloc ou une closure (block-closure en anglais), qui est un objet first-class comme en Lisp.
  •  :x -- défini un argument d'un bloc.
  • | -- code de fin de déclaration des arguments d'un bloc.

Exemple 2

[:y| y + 2] value: 3 "returns 5"

[edit] Deux exemples graphiques

Avant de nous plonger dans les détails de la syntaxe, je vais vous présenter deux scripts.

[edit] Capture d'image

Squeak supporte la manipulation d'image bitmap (classes BitBlt et WarpBlt) ainsi que les formats plus classiques comme GIF, JPEG et PNG. Le script 1 capture une partie de l'écran et la sauve dans un fichier.

Script 1 (Capturer une image)

| im |
im := Form fromUser.
GIFReadWriter putForm: im onFileNamed: 'test.gif'

Le script déclare une variable temporaire im, demande à l'utilisateur de capturer une partie de l'écran en envoyant le message unaire fromUser, et sauve la partie capturée en un fichier GIF en envoyant le message basé sur mot-clé putForm:onFileNamed: à la classe GIFReadWriter. Remarquer que le nom de la méthode est vraiment putForm:onFileNamed: avec les deux deux-points.

[edit] Transformation d'image

Tous les formats d'image sont en fait transformés en interne comme instances de la classe Form. Une Form offre diverse transformations comme le retournement, la rotation et le zoom. Le script 2 décrit comme pivoter et zoomer la portion de l'écran où la souris est située (comme illustré dans par la figure 1).

Figure 1 - Pivoter et zoomer une partie de l'écran
Figure 1 - Pivoter et zoomer une partie de l'écran

Script 2 (S'amuser avec les images)

| angle form rotatingForm |
form := Form fromDisplay: (0@0 extent: 300@300).
angle := 0.
[Sensor anyButtonPressed] whileFalse: [
   rotatingForm := (Form fromDisplay:
           (Rectangle
              center: Sensor cursorPoint
              extent: 130@66)).
   (rotatingForm
     rotateBy: angle
     magnify: 2
     smoothing: 1) display.
   angle := angle + 5].
form display

Examinons ce qui se passe dans ce script.

  • D'abord, après avoir déclaré trois variables (angle, form et rotatedForm), nous capturons et stockons dans la variable form une partie de l'écran en précisant une aire rectangulaire. L'idée est que nous puissions restaurer l'écran lorsque nous aurons fini nos manipulations. (0@0 extent: 300@300) retourne un rectangle, et @ est un message invoqué avec un nombre, qui retourne un point.
  • Ensuite nous initialisons la variable angle. Alors, tant qu'un bouton souris n'est pas pressé, nous créons un nouveau Form à partir d'une zone de l'écran sous la souris et le la stockons dans la variable rotatedForm. Sensor cursorPoint retourne la position de la souris. Rectangle center: Sensor cursorPoint extent: 130@66 retourne un rectangle centré sur la position de la souris et d'une taille de 130 par 66 pixels.
  • Nous demandons ensuite à ce form de pivoter sur lui-même tout en grossissant de 2. Noter que le nom de la méthode est rotateBy:magnify:smoothing:, et donc elle a trois arguments. Une fois qu'elle a été transformée, nous demandons au form de s'afficher lui-même. Nous incrémentons ensuite l'angle et continuons jusqu'à ce qu'une touche soit pressée.
  • Lorsqu'une touche est pressée, nous restaurons la partie originale de l'écran.

[edit] Pseudo-variables: les identifiants réservés de Smalltalk

Une pseudo-variable est une variable dont la valeur est définie par le compilateur et dont l'utilisateur ne peut changer la valeur. Il existe 6 pseudo-variables en Squeak

  • nil est l'unique instance de la classe UndefinedObject. Représente les objets non-définis
  • true est l'unique instance de la classe True. true représente la valeur vraie.
  • false est l'unique instance de la classe False. false représente la valeur fausse.
  • self représente l'objet receveur du message
  • super représente l'objet receveur tout comme self, mais la recherche de la méthode a exécuter commence dans la superclasse de la classe contenant la variable super.
  • thisContext représente la pile d'exécution.

[edit] Commentaires et identifiants

[edit] Commentaires

Un commentaire est une séquence de caractères délimités par " et ". Répéter les doubles quotes pour les inclure dans un commentaire.

Exemple 3

"a comment: any sequence of characters, surrounded by double quotes"
"comments can include the 'string delimiting' character"
"and comments can include double quote characters by ""doubling"" them" 
"comments can span many
many
lines"

[edit] Identifiants

Un identifiant est n'importe quelle séquence de caractères qui commence par un caractère alphabétique. Cette définition peut varier, aussi éviter l'utilisation de caractères non-alphabétiques pour avoir un code ressemblant à du Smalltalk.

  • Les identifiants Smalltalk sont sensibles à la casse. Ainsi heureRepas et HeureRepas sont des identifiants différents.
  • Par convention dans Smalltalk, les identifiants de plusieurs mots sur des instances de classes et de variables (d'instance, locale et temporaire) commencent en minuscule, et chaque mot suivant commence par une majuscule (i.e. ceciEstUnIdentifiant).
  • Certains identifiants, par exemple des variables globales comme Transcript et des variables de classe, commencent par une majuscule. Les noms de toutes les classes sont tous des variables globales (i.e. OrderedCollection).

[edit] Littéraux (expressions constantes)

Les expressions constantes sont des expression évaluées à la compilation. Dans la suite, --Imprimer la valeur retournée signifie "imprimer comme".

[edit] Nombres

  • Squeak supporte les petits entiers définis par la classe SmallInteger avec des primitives internes rapides.
  • Squeak supporte les entiers à l'étendue variable (lorsque nécessaire, adaptation automatique des instances de SmallInter vers des instances de LargePositiveInteger et LargeNegativeInteger) pour un petit coût en vitesse. Essayer (SmallInteger maxVal + 1) class. Nous ajoutons un au plus grand des petits entiers, et nous obtenons le plus petit de LargePositiveInteger. Essayer l'expression suivante pour voir que Squeak peut facilement manipuler des très grands nombres : 1000 factorial ou 1000 factorial / 999 factorial.
  • Squeak supporte plusieurs autres types d'entités numériques, comme les fractions (Fraction, des nombres rationnels), des points (Point). Bien qu'il n'y ait pas de littéraux prédéfinis pour ces objets, ils sont naturellement exprimés comme opérations sur des littéraux natifs (2/3 et 2@3). Essayer ce qui suit pour voir à l'oeuvre l'adaptation automatique : 1000 factorial / 999 factorial ou (9/11) + (2/11).
  • Les nombres peuvent être représentés dans diverses bases, mais la spécification de la base elle-même se fait toujours en base 10. La base pour la partie exposant est la même que pour la base principale. Ainsi :
    • 2r1010 -- Imprime la valeur 10
    • 10e2 -- Imprime la valeur 1000 (=10*10^2)
    • mais 2r1010e2 -- Imprime la valeur 40 (=10*2^2).

Example 4

Decimal integer: 1234, 12345678901234567890
Octal integer: 8r177, 8r1777777777777777777777
Hex integer: 16rFF, 16r123456789ABCDEF012345
Arbitrary-base integer: 2r1010 ==> 10
Integer with exponent: 123e2 ==> 12300, 2r1010e2 ==> 40
Float (double precision): 3.14e-10
Arbitrary-base float: 2r1.1 ==> 1.5
Float with exponent: 2r1.1e2 ==> 6.0

[edit] Caractères (instances de la classe Character)

Les caractères imprimables commencent par le signe $. Pour obtenir un caractère non imprimable, comme une tabulation ou un espace, envoyer un message à la classe Character.

Exemple 5

$x "Un caractère est n'importe quel caractère
(même non imprimable) précédé du signe dollar"
$3 "Ne soyez pas intimidé par des caractère qui
sont des chiffres"
$< "ou des symboles"
$$ "ou même le signe dollar"
Character space "Pour obtenir l'espace, le retour chariot, la tabulation"
Character cr "envoyer un message à la classe elle-même"
Character tab

[edit] Tableaux constants (instances de la classe Array)

La construction #() définie à la compilation un tableau. #() sont aussi appelé des tableaux constants. Voir la section 6 pour tableaux définis à l'exécution.

  • Les tableaux constants sont des constantes, aussi leurs éléments doivent également être des constantes. Les expressions qui peuvent représenter des éléments du tableau ne sont pas évaluées, mais analysées comme des séquences de symboles. Avec #(1 + 3), nous obtenons un tableau de trois éléments et non un tableau avec un seul élément, somme de 1 et 3.
  • Les tableaux constants peuvent contenir des tableaux constants. Le signe dièse pour les tableaux constants internes est optionnel.
  • Les identifiants et séquences de caractères dans des tableaux constants sont traités comme des symboles. Le signe dièse pour les symboles internes est optionnel.
  • Le premier éléments des tableaux est le 1.

Exemple 6

#(1 2 3 4 5) "Tableau de taille 5 comprenant les 5 entiers (1 à 5)"
#('this' #is $a #'constant' array) 
"Tableau de 5 éléments comprenant
une chaîne de caractères ('this'), un symbole (#is), 
un caractère ($a), et deux symboles (#constant et #array)."
#(1 2 (1 #(2) 3 ) 4)
"Un tableau de taille 4 comprenant deux entiers (1 et 2),
un tableau de taille 3, et un autre entier (4)."
#(1 + 2)
"Tableau de taille 3 comprenant 1, #+, et 2.
Ce n'est pas le singleton 3."

[edit] Accolades (expressions dynamiques)

Les tableaux définis avec le constructeur #() sont constants: ils sont créés lorsque la méthode est compilée, et les valeurs qu'ils contiennent lors de leur création ne peuvent être que des objets littéraux (chaîne de caractères, nombres, symboles, booléens et tableaux).

Pour créer un tableau contenant d'autres objets que des littéraux, nous devons les ajouter explicitement, comme montré dans l'exemple 7. C'est quelque chose d'ennuyeux à taper.

Exemple 7

| ar |
ar := #(nil nil nil).
ar at: 2 put: (100 factorial)
"or"
| ar |
ar := Array with: nil with: (100 factorial) with: nil

Contrairement à d'autres implémentations du langage Smalltalk, Squeak propose une solution pour définir des tableaux non littéraux en utilisant une forme compacte {,}. Les tableaux créés avec { } sont appelés des tableaux accolades car ils sont évalués à l'exécution. Les éléments d'un tableau accolade sont le résultat de l'exécution des expressions qui le compose. Les points servent à séparer les expressions.

Exemple 8

{ 1. 2 . 3 . 4 . 5 }
"Un tableau de taille 5 comprenant cinq entiers (1 à 5)"
| blop |
blop := 100 factorial.
{ $a . #brace . blop + 1}
"Un tableau de taille 3 comprenant un caractère ($a), un symbole (#brace),
et la valeur de la variable blop incrémentée de un."
{ 1 + 2 } "Un tableau de taille 1 comprenant le seul entier 3."

[edit] Chaîne de caractères (instance de la classe String)

Une chaîne de caractères est une séquence de caractères délimitée par une simple quote '. Répéter la simple quote permet de l'inclure dans la chaîne de caractères. Une chaîne de caractères est un tableau contenant des caractères. Accéder à une chaîne de caractères retourne le caractère à la position correspondante, en commençant par 1. Essayer 'bell' at: 1 et 'bell' at: 1 put: $w.

Exemple 9

'une chaîne comprend n'importe quelle séquence de
caractères entourés de simple quote'
'une chaîne peut inclure "un commentaire" en
l'entourant de la double quote'
'une chaîne peut inclure la simple en quote en
doublant'' le caractère'
'une chaîne peut contenir 
les caractères de retour à la ligne'
'' "et n'oubliez par la chaîne vide"
$a asString "la chaîne 'a'"
String with: $a

[edit] Symbole (instance de la classe Symbol)

Les symboles sont des chaînes de caractères uniques. Les symboles commencent par le caractère #.

  • La classe Symbole est une sous-classe de String, et comprend, pour une large part, les mêmes messages.
  • La première différence entre un symbole et une chaîne de caractères est que tous les symboles formés de la même séquence de caractères sont des mêmes instances. Deux instances de chaîne peuvent toutes les deux être formées des mêmes caractères 'tester un deux trois", mais tous les symboles formés des caractères #'tester un deux trois' est la même et unique instance. Cette unicité de l'instance signifie que les symboles peuvent être efficacement comparés, car l'égalité (=) est la même que l'identité (==). Essayer 'aaa' == 'aaa' et #aaa == #aaa.
  • Les symboles contenant deux points (i.e. #at:, #a:keyword:selector:) sont souvent référés comme sélecteurs par mot-clé car ils sont utilisés pour représenter les noms des méthodes.
  • Les symboles simple et double (i.e. #* ou #++) sont souvent référés comme des sélecteurs binaires. Les caractères suivants sont permis pour de tels symboles : +-/*~ <=>@%|&?!. Remarquer que # n'est pas un symbole (ou un sélecteur binaire). D'un autre coté, #'­'est un symbole (mais pas un sélecteur binaire).

Exemple 10

#'une chaîne précédée du signe dièse est un symbole'
#ouUnIdentifantPrecedeDuSigneDiese
#OuUnIdentifiantFinissantParDeuxPoints:
#ou:plusieurs:identifiants:finissant:tous:par:deux:points:
#- "Un symbole peut aussi être un dièse suivit de '-'
ou n'importe quel caractère spécial"
#+< "ou un dièse suivi de n'importe quelle paire de caractères spéciaux"

[edit] Définition de variables temporaires et affectation

[edit] Variables temporaires

Pour définir une variable temporaire, nous l'entourons de |. |a| n'a pas de valeur.

Exemple 11

| uneVariableTemporaire | "une variable temporaire"
| var1 var2 | "Deux variables temporaires"

[edit] Affectation

L'affectation d'une valeur à une variable est exprimée avec le signe _, <- ou :=. Nous vous recommandons vivement d'utiliser ce dernier :=.

Exemple 12

identifiant _ expression
identifiant <- expression
identifiant := expression
  • L'identifiant (que cela soit une variable d'instance, une variable de classe, une variable temporaire ou autre) référera ensuite à l'objet retourné par l'expression.
  • Les affectations sont des expressions ; elles retournent le résultat de la partie de droite de l'expression. Noter qu'il est considéré de mauvais style de s'appuyer sur ceci.

[edit] Messages

[edit] Les différents types de message

En Smalltalk, sauf pour les éléments syntaxiques listés dans la section précédente, tout est envoi de message. Mais il n'y a pas de concept d'opérateur, ni de surcharge. Ainsi vous pouvez définir une méthode + dans une classe de votre choix (contrairement à Java), mais il n'y pas de priorité entre méthodes mathématiques. De plus, vous ne pouvez pas surcharger une méthode, c'est-à-dire une même une méthode définie avec des arguments différents. Le code ci-dessous n'est pas possible :

Rectangle>>move(Rectangle r)
Rectangle>>move(Point p)

La simplicité du modèle a un prix.

Un message est toujours envoyé à un receveur de message, qui peut être un objet ou le résultat d'un autre message ou expression.

Smalltalk a trois types d'envoi de message: unaire, binaire et à mot clé. Cette distinction est basée sur la façon dont le nom du message est écrit.

[edit] Messages unaires

Les messages unaires sont des messages sans argument. Ils suivent le modèle syntaxique receveur nomMéthode. Le nom de la méthode est simplement une succession de caractères ne contenant pas deux points ':' comme par exemple factorial, open, class. Essayez : 2000 factorial, Browser open.

Exemple 13

89 sin
3 sqrt
Date today
Double pi
'blop' size
Browser openBrowser

Les messages unaires sont des messages sans argument. Ils suivent le modèle syntaxique receveur nomMéthode.

[edit] Messages binaires

Les messages binaires sont des messages qui ont exactement un argument et dont le nom de méthode est composé d'un ou deux caractères parmi +, -, *, /, &, =, >, |, <, ~, et @.

Noter que -- est impossible pour des raisons d'analyse syntaxique.

Exemple 14

100@100
--Affiche la valeur 100@100 "créer un point"
3+4
--Affiche la valeur 7
total - 1
total <= max
"true si total est inférieur ou égal à max"
(4/3)*3 = 4
--Imprime la valeur true "l'égalité est un message
binaire, et les Fractions sont exactes"
(3/4) == (3/4)
--Affiche la valeur false "deux Fractions égales,
mais ce ne sont pas les mêmes objets"

Les messages binaires sont des messages qui nécessitent exactement un argument et dont le nom de la méthode est composé d'un ou deux caractères parmi +, -, *, /, &, =, >, |, <, ~, et @. -- n'est pas possible. Ils suivent le modèle syntaxique receveur nomMéthode argument.

[edit] Messages à mot-clé

Les messages à mot-clé sont des messages qui ont un ou plusieurs arguments et dont les noms de méthodes inclus le caractère :. Ces messages suivent le modèle syntaxique

recever nomMéthodeMotUn: argumentUn nomMéthodeMotUn: argumentDeux.

Les deux-points dans le nom d'une méthode délimitent l'argument. Ainsi r:g:b: est une méthode avec trois arguments. playFileNamed:, at: sont des méthodes avec un argument, et at:put: est une méthode avec deux arguments. Pour créer une instance de la classe Color, on peut utiliser la méthode r:g:b: comme Color r: 1 g: 0 b: 0 qui crée la couleur rouge. Noter que les deux-points font parti du nom de la méthode.

En Java et C++, l'invocation de méthode Smalltalk Color r: 1 g: 0 b: 0 serait Color.rgb(1,0,0).

Exemple 15

1 to: 10 "créer un intervalle"
Color r: 1 g: 0 b: 0 "créer une nouvelle couleur"
MIDIFileReader playFileNamed: 'LetItBe.MID' "jouer un fichier midi"
Speaker manWithEditor say: 'Hello! I hope you will have fun with Squeak'
12 between: 8 and: 15
--Affiche la valeur true
| array |
array := #(1 2 3).
array at: 1 put: 4. "exemple d'un message à mot-clé"
array
--Affiche la valeur "#(4 2 3)"

Les messages à mot-clé sont des messages qui ont un ou plusieurs arguments. Leur nom contiennent le caractère :. Ils suivent le modèle syntaxique receveur nomMéthodeMotUn: argumentUn nomMéthodeMotUn: argumentDeux.

[edit] Composition de messages

Les trois types de message ont des ordres différents de préséance, elle permet leur composition élégamment. Les messages unaires sont toujours évalués en premier, ensuite les binaires et enfin ceux à mot-clé. Bien sûr, les parenthèses permettent de changer cet ordre. Lorsque deux messages ont la même préséance, ils sont exécutés de gauche à droite.

Règle un. Les messages unaires sont exécutés en premier, ensuite les messages binaires et finalement les messages à mot-clé: Unaire > Binaire > Mot-clé.

Exemple 16

Bot new go: 30 + 50       "créer un robot et le déplacer de 80 pixels"
Display restoreAfter : [WarpBlt test4]
"Message à mot-clé, essayez test1, test12, test3, test4, et test 5"
1000 factorial / 999 factorial
--Affiche la valeur 1000
#($t $e $s $t) at: 3
--Affiche la valeur $s
#($a $b $c $d) at: 2 factorial put: $z

Comme vous pouvez le constater, les règles de syntaxe et en particulier les messages à mot-clé, comme dans l'exemple array at: 1 put: 4, permettent d'écrire un code avec une structure approchant celle du langage naturel. C'était un des objectifs initiaux lors de la conception du langage, ainsi les enfants seraient capables de programmer plus facilement.

Règle deux. Les messages entre parenthèses sont exécutés avant les autres messages (Msg)>Unaire>Binaire>Mot-clé.


Règle trois. Lorsque des messages sont du même type, ils sont exécutés de la gauche vers la droite.

Exemple 17

1.5 tan rounded asString "identique à (((1.5 tan) rounded) asString)"
RecordingControlsMorph new openInWorld
"Une instance d'un échantillonneur est créée et affichée. Si vous
branchez un micro-phone, essayez un enregistrement !"
3 + 4 factorial
--Affiche la valeur 27 "(pas 5040) "
(HTTPSocket httpShowGif:
  'www.altavista.digital.com/av/pix/default/av-adv.gif') display

(FMSound lowMajorScaleOn: FMSound clarinet) play
"le son  Clarinet est créé et passé comme argument 
au message lowMajorScaleOn:"

[edit] Inconsistance mathématique

Les règles de composition des messages sont simples, mais inconsistantes par rapport aux priorités de calcul des quatre opérateurs de base. En effet ceux-ci sont dans Smalltalk des messages binaires, qui suivent donc les règles d'évaluation de ceux-ci. L'exemple 18 montre des situations courantes où des parenthèses supplémentaires sont nécessaires.

Exemple 18

3+4*5
--Affiche la valeur: 35 "(pas 23) Messages binaire exécutés
de gauche à droite"
3 + (4 * 5)
--Affiche la valeur 23
1 + 1/3
--Affiche la valeur 2/3 "et non 4/3"
1 + (1/3)
--Affiche la valeur 4/3
(1/3) + (2/3)
--Affiche la valeur 1

En évaluant 1000 factorial / 999 factorial nous obtenons 1000. C'est un exemple de la coercion automatique et de la gestion des nombres. Essayer d'afficher le résultat de 1000 facorial. Cela prend plus de temps à l'afficher qu'à le calculer.

[edit] Reconnaissance des mots-clés

Le point final que je souhaite aborder ici, c'est comment les messages à mots-clés sont identifiés. Cela vous aidera à comprendre pourquoi vous devez utiliser des parenthèses. Les paires de caractères [, ] et (, ) délimitent des aires distinctes. Dans de telles aires, un message à mots-clés est la plus longue séquence de mots terminés par : et qui n'est pas coupée par les caractères . ou ;. Lorsque la paire de caractères [, ] ou (, ) entoure des mots avec deux points, ces mots participent au message à mots-clés local à l'aire définie. Dans l'exemple 19, il y a deux messages distincts à mots-clés at:put: et rotatedBy:magnify:smoothing:.

Exemple 19

aDict
 at: (rotatingForm
       rotateBy: angle
       magnify: 2
       smoothing: 1)
 put: 3

Les caractères [, ], et (, ) délimitent des aires distinctes. Dans une telle aire, un message à mots-clés est la plus longue séquence de mots terminés par : qui n'est pas coupée par les caractères . ou ;. Lorsque les caractères [, ] et (, ) entourent des mots avec deux points, ces mots participent au message à mots-clés local à l'aire définie.

Astuces Au début vous aurez peut-être des difficultés avec ces règles de précédence. Commencez simplement en utilisant des parenthèses lorsque vous souhaitez distinguer deux messages ayant la même précédence.

Exemple 20

x isNil
   ifTrue:[...]

L'expression présentée en 20 n'a pas besoin de parenthèses car l'expression x isNil est unaire et est donc exécutée avant la condition.

Exemple 21

| ord |
ord := OrderedCollection new.
(ord includes: $a)
   ifTrue:[...]

L'expression présentée en 21 a besoin de parenthèses car les messages includes: et ifTrue: sont à mots-clés. Sans les parenthèses le message inconnu includes:ifTrue: est envoyé à la collection.

[edit] Séquences d'expressions

Les expressions (messages, affectations,...) séparées par des points sont exécutées en séquence. Notez qu'il n'y a pas de point entre la déclaration d'une variable et l'expression suivante. La valeur d'une séquence est la valeur de la dernière expression. Les valeurs retournées par toutes les expressions sauf la dernière sont ignorées. Notez aussi que le point est un séparateur et non une instruction de fin. Aussi, un point final est optionnel dans une séquence.

Exemple 22

|box|
box := 20@20 corner: 60@90.
box containsPoint: 40@50

[edit] Messages en cascade

Smalltalk permet d'envoyer plusieurs messages à un même objet avec le constructeur ; qui est appelé cascade dans le jargon Smalltalk.

Expression Msg1 ; Msg2

Exemple 23

Transcript show: 'Squeak '.
Transcript show: 'est ' , 'très'.
Transcript show: 'fun '.
Transcript cr.
"est équivalent à"
Transcript
  show: 'Squeak ';
  show: 'est ', ' très';
  show: 'fun ';
  cr

Notez que l'objet recevant des messages en cascade peut être le résultat d'un message. Dans l'exemple ci-dessous, le receveur du message en cascade add: est une collection ordonnée fraîchement créée suite à l'évaluation de OrderedCollection new.

Exemple 24

(OrderedCollection new) add:25 ; add: 35

L'exemple précédent est un des pièges le plus connu de Smalltalk. Regardons de plus près. Premièrement vous devez savoir que la méthode add: retourne l'élément ajouté et non la collection ; les autres valeurs sont abandonnées. Aussi, le résultat de l'expression complète est celui du dernier message de la cascade add: 35, à savoir 35. Nous avons besoin de retourner le receveur de la cascade de message, ici la collection ordonnée créée. En fait, nous avons besoin de retourner self. C'est ce que fait la méthode yourself. L'exemple 25 retourne bien la collection ordonnée contenant les éléments 25 et 35.

Exemple 25

(OrderedCollection new) add: 25 ; add: 35 ; yourself

[edit] Primitives

Dans Smalltalk tout est objet, et les calculs sont réalisés en exécutant des méthodes en réponse à des envois de messages. Cependant, tout ne peut pas être réalisé dans ce contexte. Le système devrait s'appuyer sur un petit ensemble de méthodes définies dans le langage d'implantation (C, C++, assembleur) de la machine virtuelle. Certaines méthodes invoquent des fonctionnalités appelées primitives. En tant que développeur Smalltalk, vous n'avez pas à vous soucier si le méthode que vous invoquez est une primitive.

Pour vous donnez une idée des primitives, les fonctionnalités suivantes sont implantées comme des appels de primitives : allocation mémoire (new, new:), manipulation de bit (bitAnd:, bitOr:, bitShift:), calculs sur pointer et entier (+, -, <, >, *, /, =, ==, ...), et accès de table (at:, at:put:). De telles méthodes appellent des primitives à l'aide de l'instruction <primitive: aNumber>. Après cette instruction il y a du code qui est exécuté lorsque la primitive échoue. Dans le cas de primitives ne pouvant pas être exprimées dans le paradigme objet, la méthode primitiveFailed est appelée.

Méthode 2

ProtoObject>>== anObject
  "Primitive. Answer whether the receiver and the argument
  are the same 
  object (have the same object pointer). Do not redefine
  the message == in any other class! Essential. No Lookup.
  Do not override in any subclass.
  See Object documentation whatIsAPrimitive."
  <primitive: 110>
  self primitiveFailed

L'autre utilité des primitives est d'optimiser quelques méthodes cruciales. L'idée est que le système puisse fonctionner même sans les primitives, mais plus lentement. La méthode suivante montre que la méthode @ utilise la primitve 18. Ici la création du point est clairement exprimable en Smalltalk. Aussi, le code après la primitive est juste la création d'un point, illustrant ce que fait la primitive. Notez que ce code ne sera jamais exécuté, à moins que la primitive échoue, chose très rare.

Exemple 26

Integer>>@ y
  "Primitive. Answer a Point whose x value is 
  the receiver and whose y value is the argument. 
  Optional. No Lookup. See Object documentation
  whatIsAPrimitive."

  <primitive: 18>
  ^Point x: self y: y

[edit] Fermetures lexicales(block-closures)

Les fermetures ou blocs constituent une fonctionnalité très puissante de Smalltalk, héritée des langages fonctionnels. Les blocs sont des méthodes anonymes ou des séquences de messages dont l'exécution est différée. Dans leur aspect fonctionnel, un bloc est similaire à une fonction mathématique. Les blocs sont des instances de la classe BlockContext.

La fonction x-->2x+1 est représentée par le bloc

[:x|2*x+1]

f(x)-->2x+1 peut être représentée par :

|f|
f:=[:x|2*x+1]

f(3) par :

f value: 3

Exemple 27

|f|
f := [ :x| 2*x + 1 ].
f value: 3
--Valeur affichée : 7

Note pour les programmeurs Java. Les Innerclasses furent introduites dans Java car le langage n'offre pas les blocs.

Un bloc peut avoir zéro ou plusieurs arguments définis entre les caractères [ et |. Ils commencent par le caractère  :. Les blocs peuvent également déclarer des variables locales délimitées par deux |, et ensuite avoir une séquence de message. La valeur d'un bloc est la valeur de sa dernière expression sauf s'il y a un retour explicite par un ^.

Message important 1

[ :variable1 :variable2 |
   | blockTemporary1 blockTemporary2 |
   expression1.
   ...variable1 ...
   expressionz ]

Exemple 28

[2+3+4+5]                       "un bloc sans argument"
[ :x | x + 3 + 4 + 5 ]          "un bloc avec 1 argument"
[ :x :y | x + y + 4 + 5 ]       "un bloc avec 2 arguments"
[ :x :y :z | x + y + z + 5 ]    "un bloc avec 3 arguments"
[ :x :y :z :w | x + y + z + w ] "un bloc avec 4 arguments"

Un bloc est une séquence de messages à l'exécution différée, dans le sens où les messages qu'il contient ne sont pas exécutés lorsque le bloc est créé. Pour exécuter le bloc et obtenir sa valeur, nous utilisons les méthodes value, value:, value:value:, .... Si vous avez un bloc avec plus de quatre paramètres, vous devez utiliser le message valueWithArguments: et passer les arguments dans un tableau. Notez que cela révèle souvent un problème de conception.

Exemple 29

[ 2 + 3 + 4 + 5 ] value
[ :x | x + 3 + 4 + 5 ] value: 2
[ :x :y | x + y + 4 + 5 ] value: 2 value: 3
[ :x :y :z | x + y + z + 5 ] value: 2 value: 3 value: 4
[ :x :y :z :w | x + y + z + w ] value: 2 value: 3 value: 4 value: 5

En fait, les blocs sont des fonctions qui capturent l'environnement dans lequel ils sont définis, ainsi ils peuvent faire référence à des variables qui ne sont pas définies dans le contexte du bloc. C'est pour cela qu'ils sont appelés fermetures lexicales. Parce qu'ils font une fermeture lexicale, ils peuvent se référer aux variables visibles dans le contexte de définition du bloc. Notez que Squeak, contrairement à d'autres Smalltalk, n'a pas une vraie fermeture car les variables du bloc sont stockées dans la méthode définissant le bloc, ce qui introduit quelques problèmes (ndlt: avec la récursivité).

Exemple 30

| index bloc |
index := 0.
bloc := [ index := index +1 ].
bloc value
--Valeur retournée : 1
index := 3.
bloc value
--Valeur retournée : 4

Les blocs peuvent être assignés à des variables et passés comme arguments de méthode. Notez que pour des raisons de performance, il est préférable d'éviter des références à des variables extérieures au bloc ou bien d'utiliser des retours explicites. En écrivant des blocs qui ne font référence qu'à leurs arguments cela permet au compilateur de les optimiser drastiquement.

Squeak, dans sa version 3.4, ne supporte par vraiment une fermeture lexicale complète (ndlt : il y a du changement pour 3.9). Les blocs sont simulés (les arguments de bloc sont définis comme des méthodes temporaires de la méthode définissant le bloc) et non implantés comme dans les autres version de Smalltalk. Cela vient du fait que Squeak est basé sur une des première implantation de Smalltalk. Cette situation est amenée à changer car de nouvelles implantations supportant une véritable fermeture lexicale sont en développement.

[edit] Expressions retournées

Retourner une expression se fait en la préfixant du caractère ^>. À l'intérieur du corps de la méthode ou du bloc, une expression de retour est utilisée pour terminer la méthode et pour délivrer l'expression en tant que résultat de la méthode.

Très important. Le caractère ^ est un mécanisme d'échappement. Une expression de retour dans une expression d'un bloc emboîté, terminera la méthode, comme montré dans l'exemple 31.

Exemple 31

lorsque l'expression ^ x@y est exécutée, la méthode 
detect: s'échappe de l'itération courante et la retourne

TwoLevelSet>>detect: aBlock

firstLevel keysAndValuesDo: [ :x :v |
v do: [ :y | (aBlock value: x@y) ifTrue: [ ^x@y ] ] ].
^nil

[edit] Structures de contrôle

Comme je l'ai déjà mentionné, dans Smalltalk il n'y a pas d'instructions spécifiques pour les boucles, les tests ou les exceptions. Les messages à mots-clés avec des blocs suffisent pour les exprimer.

[edit] Tests (le receveur est un booléen)

Il y a quatre méthodes définies dans la classe Boolean, True et False qui définissent une exécution conditionnelle : ifTrue:ifFalse:, ifFalse:ifTrue:, ifTrue: et ifFalse:.

Ces méthodes ont le comportement suivant :

aBooleanExpression 
   ifTrue: 
      trueAlternativeBlock 
   ifFalse: 
      falseAlternativeBlock

et

aBooleanExpression  
   ifFalse: 
      falseAlternativeBlock 
   ifTrue: 
      trueAlternativeBlock

retournent la valeur de trueAlternativeBlock si le receveur est true et falseAlternativeBlock s'il est false. Sinon, une erreur est signalée.

aBooleanExpression 
   ifTrue: 
      alternativeBlock 

retourne nil si le receveur est false, signale une erreur si le receveur n'est pas un booléen, sinon retourne le résultat de l'évaluation l'argument alternativeBlock.

  • Symétriquement :
aBooleanExpression 
   ifFalse: 
      alternativeBlock 

retourne nil si le receveur est true, signale une erreur si le receveur n'est pas un booléen, sinon retourne le résultat de l'évaluation de l'arguement alternativeBlock.

Notez que les blocs utilisés sont des blocs sans argument, et comme tout bloc ils peuvent contenir une séquence de messages. Toutes ces expressions conditionnelles sont simplement des méthodes définies dans la classe Boolean. Notez aussi que le compilateur les optimise drastiquement, les messages ne sont en fait pas envoyés.

Exemple 32

10 factorial isOdd
   ifTrue: 
      [ Transcript show: 'Nombre impair'; cr ]
   ifFalse: 
      [ Transcript show: 'Nombre pair'; cr.
      Beeper beep ]

Composer des expressions booléennes. La classe Boolean définie aussi des méthodes pour composer des expressions booléennes : & aBoolean (et), and: aBlock (lazy and), | aBoolean (ou), or: aBlock (lazy or), et xor: aBlock (ou exclusif).

[edit] Itérateurs conditionnels(le receveur est un bloc)

En plus des expressions conditionnelles, la classe BlockContext définie les méthodes suivantes qui implantent les itérateurs conditionnels : whileTrue, whileTrue:, whileFalse et whileFalse:.

Ces méthodes ont le comportement suivant :

aBlock whileTrue

évalue le receveur et continue de l'évaluer tant qu'il retourne true.

aBlock whileTrue:
      anotherBlock

évalue le receveur. Si le receveur retourne true, évalue anotherBlock et répète comme montré dans l'exemple 33.

  • whileFalse et whileTrue: sont les symétriques des deux méthodes précédentes.

Exemple 33

| counter |
counter := 0.
[ counter < 100 ] whileTrue:
   [ counter := counter + 1.
   Beeper beep ]

La définition des méthodes whileTrue: et whileTrue est un autre exemple de l'utilisation des boucles conditionnelles (voir méthode 3). Notez aussi que pour ces méthodes, le compilateur optimise leur invocation à un point tel qu'elles ne sont pas exécutées sous cette forme.

Méthode 3

 BlockClosure>>whileTrue: aBlock
  ^ self value
      ifTrue:
         [ aBlock value.
         self whileTrue: aBlock ]

BlockClosure>>whileTrue
  ^ [ self value ] whileTrue: []

[edit] Énumérations (le receveur est un entier)

La classe Integer définie les boucles inconditionnelles suivantes timesRepeat:, to:do: et to:by:do:.

Ces méthodes ont le comportement suivant :

startInteger timesRepeat: 
   aBlock

évalue l'argument aBlock le nombre de fois représenté par le receveur.

startInteger to: stopInteger do:
   aOneArgBlock 

évalue aOneArgBlock avec chaque élément de l'intervalle comme argument, comme montré par l'exemple 35 qui définie la fonction factorielle.

startInteger to: stopInteger by: stepInteger do:
   aOneArgBlock 

évalue aOneArgBlock avec chaque élément de l'intervalle comme argument.

Exemple 34

4 timesRepeat: [ Beeper beep ]
1 to: 3 do: [ :i | Transcript show: i printString ;cr ]
"Envoie #to:do: (avec deux paramètres) à l'entier 1"
(1 to: 3) do: [ :i | Transcript show: i printString ;cr ]
"Envoie #do: à l'intervalle donné par l'évaluation de '1 to: 3'"

Exemple 35

| tmp |
tmp := 1.
2 to: self do: [ :i | tmp := tmp * i ].
tmp

[edit] Énumérations (le receveur est une collection)

Smalltalk définie aussi de puissantes méthodes d'itération sur des collections. Ces méthodes ont été très largement reprises dans d'autres langages (ndlt: même très récent comme C#, mais malheureusement sans le confort syntaxique de Smalltalk'). Les principales méthodes sont do:, collect:, select:, reject:, detect:, detect:ifNone:, with:do: et inject:into:.

Le comportement de ces méthodes est le suivant :

aCollection do:
   aOneArgBlock

applique aOneArgBlock, un bloc nécessitant un argument, à chaque élément de la collection.

aCollection collect:
   aOneArgBlock 

retourne une collection contenant tous les résultat obtenus en appliquant le block aOneArgBlock à chaque élément de la collection.

aCollection with: anotherCollection do:
   aBinaryBlock

itération en parallèle sur chaque élément des deux collections et exécution d'un bloc, nécessitant deux arguments, avec les éléments de chaque collection

Exemple 36

#(15 10 19 68) do:
   [ :i | Transcript show: i printString ; cr ]
#(15 10 19 68) collect:
   [ :i | i odd ]
 --Valeur retournée : #(true false true false)
#(1 2 3) with: #(10 20 30) do:
   [ :x :y | Transcript show: (y ** x) printString ; cr ]
aCollection select:
   aOneArgPredicateBlock 

retourne une collection représentant tous les éléments de la collection satisfaisant le bloc aOneArgPredicateBlock. Le bloc doit prendre un argument et retourner un booléen.

aCollection reject:
   aOneArgPredicateBlock

retourne une collection représentant tous les éléments de la collection ne satisfaisant pas le bloc aOneArgPredicateBlock.

aCollection detect:
   aOneArgPredicateBlock

retourne le premier élément satisfaisant le bloc aOneArgPredicateBlock. Une erreur est signalée si aucun des éléments ne satisfait le bloc.

aCollection detect:
   aOneArgPredicateBlock 
ifNone: aNoneBlock 

retourne le premier élément satisfaisant le bloc aOneArgPredicateBlock. Si aucun élément ne le satisfait, retourne la valeur retournée par aNoneBlock

Exemple 37

#(15 10 19 68) select: [ :i | i odd ]
--Retourne la valeur : #(15 19)
#(15 10 19 68) reject: [ :i | i odd ]
--Retourne la valeur : #(10 68)
#(12 10 19 68 21) detect: [ :i | i odd ]
--Retourne la valeur : 19
#(12 10 12 68) detect: [ :i | i odd ] ifNone:[ 1 ]
--Retourne la valeur : 1
aCollection inject: aStartValue into: 
   aBinaryBlock 

applique le bloc aBinaryBlock à tous les éléments du receveur, accumulant le résultat dans le premier argument en commençant par la valeur aStartValue

Exemple 38

|acc|
acc := 0.
#(1 2 3 4 5) do: [ :element | acc := acc + element ].
acc
--Retourne la valeur : 15
"Est équivalent à"
#(1 2 3 4 5) inject: 0 into:
   [ :acc :element | acc + element ]

[edit] Exceptions

Squeak supporte les exceptions standards ANSI. Les exceptions sont également des objets. De même ce ne sont pas des instructions spécifiques. Ce sont sont juste des méthodes associées à des blocs. Pour attraper une exception utilisez la méthode on: anException do: aUnaryBlock sur un bloc. Pour lever une exception utilisez la méthode signal définie dans la classe Exception.

Exemple 39

[| tmp |
   10 to: -10 by: -1 do:
      [ :i | Transcript show: (100 / i) printString ; cr ] ]
   on: ZeroDivide
   do: [:ex | ]

Les messages les plus importants définis dans la classe BlockContext sont :

  • aTerminationBlock qui évalue aTerminationBlock après avoir évalué le receveur, que l'évaluation de celui-ci soit complète ou non.
  • ifCurtailed: aTerminationBlock, qui évalue le receveur, et si celui-ci se termine anormalement, évalue aTerminationBlock.
  • on: exception do: handlerActionBlock qui évalue le receveur dans la portée d'un gestionnaire d'exception, handlerActionBlock.

Exemple 40

["code cible, qui peut avorter"]
   ensure:
      ["code qui sera toujours exécuté après le code cible,
      quoiqu'il arrive"]

["code cible, qui peut avorter"]
   ifCurtailed:
      ["code qui sera exécuté lorsque le code cible
      se termine anormalement"]

["code cible, qui peut avorter"]
   on: Exception
   do:
      [:exception |
      "code qui sera exécuté lorsque l'exception
      identifiée est levée."]

Les exceptions ont beaucoup de possibilités, comme d'être reprises ou redémarrées, ou encore lever d'autres exceptions. Parcourez la classe Exception pour en savoir plus.

[edit] Définition de classe

Il n'y a pas d'instruction spécifique pour définir une classe en Smalltalk. Une classe est créée en envoyant des messages à la superclasse de la classe que nous souhaitons définir. Différents types de classes peuvent être créés selon que leurs instances sont de taille fixe ou que leurs instances peuvent avoir une taille arbitraire comme c'est le cas pour les tableaux.

[edit] Définition de classe ordinaire

Ce premier type de classe est créé en utilisant le message subclass:instanceVariableNames:classVariableNames:poolDictionaries:category: et dans 99% des cas vous utiliserez ce message pour créer vos classes. Les instances de telles classes, en ayant des variables d'instances nommées, sont d'une taille fixe.

Classe 1

SuperClass subclass: #NameOfClass
   instanceVariableNames: 'instVarName1 instVarName2'
   classVariableNames: 'ClassVarName1 ClassVarName2'
   poolDictionaries: 
   category: 'Major-Minor'

[edit] Définition de classe variable

Le second type de classe est créé en utilisant un des messages suivants : variableSubblass:..., variableByteSubclass:..., variableWordSubclass:.... Ces types de classe sont utilisés pour créer des objets indexables, comme les instances de Array, ByeArray et WordArray. Les instances de telles classes sont d'une taille arbitraire qui est précisée lors de l'instanciation avec le message new: anInteger. Les différents messages indiquent le type d'entité indexable :

  • variableSubblass:... spécifie que les instances ont des variables indexées qui contiennent des pointeurs sur des objets.
  • variableByteSubclass:... spécifie que les instances ont des variables indexées qui contiennent des octets (bytes).

Je les ai exposées ici, mais il est très rare que vous les utilisiez.

Classe 2

SuperClass variableSubclass: #NameOfClass
   instanceVariableNames: 'instVarName1 instVarName2'
   classVariableNames: 'ClassVarName1 ClassVarName2'
   poolDictionaries: 
   category: 'Major-Minor'

SuperClass variableByteSubclass: #NameOfClass
   instanceVariableNames: 'instVarName1 instVarName2'
   classVariableNames: 'ClassVarName1 ClassVarName2'
   poolDictionaries: 
   category: 'Major-Minor'

SuperClass variableWordSubclass: #NameOfClass
   instanceVariableNames: 'instVarName1 instVarName2'
   classVariableNames: 'ClassVarName1 ClassVarName2'
   poolDictionaries: 
   category: 'Major-Minor'

[edit] Définition de messages

Les méthodes sont définies en écrivant dans le navigateur de classes (browser) la signature de la méthode suivi du corps de la méthode et compilées avec l'item Ok (accept) du menu contextuel. La classe dans laquelle la méthode est définie n'est pas explicitement mentionnée, comme montré dans Méthode 4. La navigateur compile la méthode dans la classe où la méthode est définie. Notez qu'il existe quelques messages pour demander explicitement à la classe de compiler une méthode, mais ces messages sont utilisés par le compilateur ou l'environnement du navigateur pour créer des méthodes. Normalement vous n'avez pas besoin de les connaître.


Les méthodes retournent toujours une valeur ; il y a un ^ self implicite à la fin de chaque méthode pour assurer le retour d'une valeur. Dans Méthode 4, la méthode d'instance (de String) retourne explicitement une valeur ; tandis que dans Méthode 5, méthode de classe définie dans la classe Browser, il n'y a pas de valeur retournée explicitement, ainsi la méthode retourne self, qui représente la classe Browser elle-même, puisque cette méthode est une méthode de classe.

Méthode 4

lineCount
   "Answer the number of lines represented by the  receiver,
   where every cr adds one line."
   | cr count |
   cr Character cr.
   count 1 min: self size.
   self do:
      [ :c | c == cr ifTrue: [count count + 1] ].
   ^ count

Méthode 5

openBrowser
   "Create and schedule a BrowserView with default browser label. 
   The view consists of five subviews, starting with the list
   view of system categories of SystemOrganization.
   The initial text view part is empty."
   | br |
   br := self new.
   self
      openBrowserView: (br openEditString: nil)
      label: br defaultBrowserTitle

[edit] Ce qu'il faut retenir

La syntaxe de Squeak est basée sur les éléments suivants :

  1. six identifiants réservés, aussi appelés pseudo-variables : true, false, nil, self, super et thisContext ;
  2. des expressions constantes appelées objets littéraux : Nombres, Caractères ($a), Chaînes de caractères ('Une chaîne, oui !'), des symboles qui sont des chaînes de caractères uniques unSymboleUnique, des tableaux (#(a #(b 1))) ;
  3. des identifiants et affectation (:=:=, _, <-) ;
  4. des tableaux dynamiques, aussi appelé tableaux accolades ({1.2 . 3*5}) ;
  5. des messages, qui sont de trois types : messages unaire (asString, new), binaire (+, <=, &, @,...) et à mots-clés (at:, at:put:, r:g:b:). Les messages unaires ont la plus grande précédence, ensuite les binaires puis ceux à mots-clés. Les messages avec la même précédence sont évalués de gauche à droite ;
  6. fermeture lexicale ou bloc sont des séquences anonymes de messages à exécution différée ([:x | x + 2] value: 4).

Basée sur ces éléments syntaxiques, les expressions conditionnelles (i.e. ifTrue:ifFalse:, whileTrue:), les itérations (i.e. timesRepeat, to:do:, do:, collect:, select:) et les exceptions (i.e. on:to:, ifCurtailed:) sont naturellement exprimées sans avoir besoin d'instructions spécifiques.

Personal tools