Dans ce cours, nous allons aborder la manière de composer
des messages et de voir comment marche la précédence, c'est-à-dire
qui prend le pas par rapport à un autre.
Si on regarde, la question qui se pose c'est "Qu'est-ce
qui se passe quand j'ai une séquence de messages unaires?"
Là, j'ai écrit l'expression suivante "1000 factorial class name".
Il se trouve que ça s'exécute exactement de la même
manière que si j'avais mis toutes ces parenthèses et on
voit que c'est embêtant d'avoir toutes ces parenthèses.
Ce que le système va faire, c'est que quand vous avez des
messages qui sont d'un même niveau, ça veut dire
binaires, unaires ou à mots-clefs, ça marche dans les
trois cas, il va toujours les évaluer de gauche à droite.
Là, je vais envoyer le message factoriel à 1000.
Après, je vais envoyer le message classe aux résultats de factoriel.
Et après, je vais envoyer de message name à ce
nouvel objet et je vais obtenir LargePositiveInteger.
Pour votre info, factoriel 1000, c'est quand même un gros nombre.
Vous pouvez aussi essayer avec factoriel 10000 si vous en
avez envie, c'est un tout petit peu plus long.
Là ce que l'on voit, ça veut dire qu'on a des messages,
on a des parenthèses pour exécuter des expressions en
premier lieu, ensuite les messages unaires, ensuite les
messages binaires, les messages à mots-clefs et après
quand il y a égalité, on fait de gauche à droite.
Regardons un exemple.
Là, j'ai un message unaire, squared, et un
message binaire, +.
Donc, c'est le message unaire qui gagne.
Donc, j'envoie d'abord squared et, en plus, en deuxième
lieu, j'envoie le message +.
Et donc j'obtiens bien 11, c'est correct.
Maintenant, là j'ai un autre cas de figure, je vais lever
à la puissance, raisedTo, j'ai un message binaire et un
message à mot-clef, donc c'est le message binaire qui gagne.
Premièrement, ça va me faire 5 puis après, je vais faire
raisedTo, ça me rend 32, c'est correct.
Là, c'est un exemple un peu plus funky, les couleurs en
Pharo sont des objets, donc j'ai la classe couleur.
Là, j'ai trois messages unaires, j'ai gray, white et black.
Et j'ai deux messages binaires, j'ai = et -.
Qu'est-ce qui va se passer ?
Le système va d'abord exécuter tous les messages unaires.
Je vais obtenir la couleur gray, la couleur white et la couleur black.
Là donc, il faut que, maintenant, j'envoie des messages,
il me reste à choisir entre le message - et le message =.
Là, je vais envoyer message moins à l'objet gray avec
comme argument white, ça va me donner la couleur black.
Après, je vais comparer mes deux couleurs et ça me donne
que black = black, donc c'est vrai.
Donc là, c'est plus un exemple pour vous montrer qu'on
peut aussi faire de la conversion automatique avec Pharo,
c'est une sorte de clin d'œil un petit peu.
J'ai cette expression 1 class maxVal + 1, donc j'ai deux
messages unaires, class et maxVal, et puis j'ai un message binaire.
Comment ça s'exécute cette expression?
Je vais envoyer le message classe au petit entier 1, il
me dit "Ben oui, tu es un petit entier puisque tu es 1",
c'est quand même très optimisé.
Et maintenant, je vais envoyer à la classe, puisque c'est
le résultat de 1 classe, je vais lui envoyer le message maxVal.
Qu'est-ce que c'est que le message maxVal?
C'est quel est le plus grand nombre que tu peux encoder
sur un petit entier, c'est ça ce que ça veut dire.
Et donc là ça me rend ce nombre à quelques chiffres qui finit par 23.
Et à ce nombre maintenant, je vais lui envoyer le message plus 1.
Je n’obtiens forcément pas un petit entier, puisque ça, c'est
la valeur qui tient sur un petit entier, donc ça sera
forcément quelque chose qui n'est pas un petit entier.
Là finalement, je lui demande "Qu'est-ce que c'est la classe de ce nombre?"
Je mets des parenthèses, j'envoie class et ça me dit que
c'est un LargePositiveInteger. Celui-là, c'est le plus
grand des petits entiers et celui-là, c'est le plus petit
des grands entiers. Là, j'ai mis des parenthèses parce
que si je n'avais pas mis de parenthèses, class aurait été envoyé à 1.
Ce n'est pas ce que je veux, je veux envoyer class aux
résultats de cette expression.
Imaginons là, j'ai créé un rectangle et je veux obtenir
le point en bas à droite du rectangle.
J'ai écrit ça, je l'exécute, ça plante.
Le système me dit "Je ne comprends pas: 100 ne comprend
pas le message bottomRight " Pourquoi?
Parce que bottomRight, c'est un message unaire et il est
exécuté avant tous les autres, donc il est envoyé à 100, son receveur.
Mais 100 ne comprend pas cette api puisque c'est de l'api
de la classe rectangle. Donc là, je suis obligé de mettre
des parenthèses, ce que j'ai fait ici dans cette expression.
Comment ça se passe ?
L'expression parenthésée est exécutée en premier, dans l'expression
parenthésée, j'ai deux messages binaires qui sont
exécutés qui me créent des points.
Donc, j'ai mes deux points qui sont créés.
J'envoie le message extent à un point qui me crée un rectangle.
L'idée, c'est que j'ai un point 0,0 et puis après je lui
passe extent, c'est 100,100, donc
ça va me donner ce rectangle-là.
Et maintenant, je lui demande quelle est la valeur.
BottomRight à la fin vient d'envoyer un rectangle et il
me donne la valeur du point qui est ici et qui est bien le point 100,100.
Ce que je vous ai dit dans Pharo, c'est que c'était très
simple: en fait, il n'y a que des messages.
Donc, + est un message comme les autres, il n'y a pas de
précédence mathématique. L'avantage, c'est qu'on peut
utiliser + pour faire des domaines spécifiques languages,
on peut utiliser + entre des objets qui n'ont rien à voir
avec des objets mathématiques. Typiquement en Java, vous
ne pouvez pas le faire. En C++, vous pouvez le faire
quand vous redéfinissez des opérateurs.
En Pharo, la solution, c'était + est un message
comme les autres. C'est un choix de simplicité.
Par contre, il y a un prix, c'est qu'il n'y a pas de
précédence mathématique.
Dans cette expression, j'ai deux opérateurs ou deux messages binaires.
J'exécute de gauche à droite.
Je fais 5 et puis ça me rend 50 et ce n'est pas ce qu'on
m'a appris à l'école. Pour obtenir ça, je vais devoir
désambiguïser, donc je vais utiliser des parenthèses autour de multiplié.
Donc effectivement, il faut faire attention quand on
manipule des opérations arithmétiques dans Pharo parce
que les opérateurs mathématiques sont juste des messages.
Un autre exemple, si je fais 1/3 + 2/3, je ne vais pas
obtenir ce qu'il faut parce que le système va d'abord
exécuter cette expression-là puisque ça va de gauche à droite.
Donc maintenant, si je mets des parenthèses, j'obtiens bien le bon résultat.
Là, j'ai vraiment un point intéressant à soulever, c'est
que j'obtiens le petit entier 1 quand je fais 1/3 + 2/3.
Je n'obtiens pas 1,0 quelque chose ou je n'obtiens pas 0,999.
C'est des fractions, elles sont exactes et j'obtiens des calculs exacts.
En résumé, on aura vu qu'il y a trois sortes de messages,
maintenant vous devez le savoir: unaires, binaires et à mots-clefs.
On exécute de manière prioritaire les parenthèses
unaires, binaires et à mots-clefs.
Quand on est à égalité, si j'ai deux
messages unaires, je vais le faire de gauche à droite.
Il n'y a pas de précédence mathématique parce que les
messages mathématiques sont juste des messages comme les autres.
Et ce qui est différent d'avec la plupart des langages, c'est
que les arguments sont placés à l'intérieur de la
structure comme dans beetween: and: