Bonjour à tous.
Aujourd'hui, nous allons parler des erreurs qui sont
fréquemment commises par les développeurs Pharo, y compris moi-même.
Nous allons essayer de voir comment on peut repérer ces
erreurs facilement et les corriger rapidement.
Ici, nous avons un bout de code qui, quand il est
exécuté, un débugger s'ouvre et nous dit
que le message self a été envoyé à un objet, et que cet
objet ne comprend pas le message self.
On peut se dire, self, en général, ce n'est pas trop un
message qu'on envoie, il y a donc probablement une erreur
quelque part dans le code.
En regardant un peu, on voit qu'ici il manque un
point et l'exécution se passe comme si
self était un message qui était envoyé au résultat de DiceHandle new.
Comme la classe DiceHandle n'a pas de méthode self, on a
ce débugger qui s'ouvre.
La solution c'est d'ajouter ce point à la fin de la
première ligne.
Un autre problème qu'on obtient régulièrement, ce sont
des messages qui a priori ne devraient pas être combinés
et qui sont combinés. Là, on a une erreur qui nous
indique que include if true n'existe pas, include existe,
if true existe, include if true n'existe pas.
En regardant de plus près, on se rend compte ici que
effectivement on envoie le message include ifTrue au
receveur X avec deux paramètres, 33 et un block.
Ça ne marche pas. Pharo ce qu'il fait quand il voit un
mot-clé, il essaye de regarder tous les mots-clés qui
suivent, il les prend tous, il considère que ça c'est un
seul envoi de message. Ce qui manque ici, c'est une paire
de parenthèses pour dire que le message ifTrue envoie au
résultat de X include 33.
De la même façon, assert include n'existe pas, ce qu'on a
voulu faire c'est assert sur le résultat d'include, et
donc il manque des parenthèses ici.
Il ne faut pas hésiter à mettre des parenthèses quand on
a plusieurs messages à mots-clés dans la même expression,
pour bien les séparer car Pharo va essayer de regrouper
tous les mots-clés ensemble. et il considère que c'est un seul message.
Dans cet exemple-ci, on souhaiterait dans la variable
numbers avoir une collection de nombres, et pour le
moment cette collection ne contient qu'un seul nombre, le nombre 35.
Cependant, si on regarde ce qui est dans numbers, ce n'est
pas une collection, c'est le nombre 35.
Il y a donc un problème.
De la même façon, sur ce code-là, si
j'envoie le message new à la classe dice, j'obtiens le
nombre 6 plutôt qu'un dé à 6 faces.
En fait, c'est le même problème dans les 2 exemples.
Si on regarde plus précisément, le fait d'envoyer
yourself après add, va corriger le problème.
Pourquoi? Parce que add retourne son paramètre.
Et donc, OrderedCollection new add 35, retourne 35.
Si on ajoute la cascade et yourself, on s'assure d'obtenir
le receveur à la fin et numbers est bien une collection de nombre.
Donc les solutions ici, c'est bien d'ajouter yourself à
la fin de chaque envoi de message.
Voici un autre problème.
On a une classe book, une méthode borrow, et quand on l'exécute
on obtient le message que nil ne comprend pas ifFalse.
On envoie le message ifFalse ici à nil, ça veut dire que
in library à la valeur nil qui est la valeur par défaut
pour toutes les variables, ce qu'on peut se dire c'est
que probablement in libray n'a jamais initialisé.
Donc il faut donc mettre une valeur par défaut dans cette variable-là.
On peut corriger ça assez facilement, en ajoutant une
méthode initialize qui dès la création de l'instance de
chaque instance de la classe book, va mettre la valeur
true dans la variable d'instance in library.
Sauf que si on exécute ce code-là maintenant, on va avoir
un autre message d'erreur qui est class true ne comprend
pas le message ifFalse.
D'où est-ce que ça vient ?
Ce qu'on a mis ici c'est une classe, ce n'est pas un
booléen c'est une classe.
Le booléen c'est true avec un T minuscule.
Les classes prennent en général une majuscule.
Et donc true avec un T majuscule c'est une classe et true
avec un T minuscule, c'est la seule instance de la classe true.
Voici un autre problème.
On a une méthode roll dans une classe dice, on s'attend à
ce que quand on fait rouler un dé, on obtienne un nombre
entre 1 et le nombre de faces du dé, sauf que là, quand
on fait rouler le dé, on obtient un dé et pas
la face sur laquelle on est tombé.
La méthode que je viens de vous montrer est équivalente à
la méthode ci-dessous, c'est-à-dire que, par défaut, une
méthode qui ne renvoie rien renvoie self.
C'est-à-dire que notre méthode roll, quand elle va s'exécuter,
elle va retourner le dé et non pas le résultat d'envoyer
at random à
la collection faces.
Donc le même problème dans un exemple un petit peu différent.
Ici on crée une méthode new dans la classe dice,
donc dans dice class ce qu'on veut c'est faire une
nouvelle méthode pour créer des instances de la classe
dice qui initialise, par défaut, le nombre de face à zéro.
Si on envoie le message new à la classe dice, ce qu'on va
obtenir c'est la classe dice elle-même plutôt qu'une
nouvelle instance de la classe dice.
Dans les 2 cas, le fait qu'il n'y ait pas de return self
et self, par défaut, c'est le receveur.
Donc dans le cas d'une méthode de classe, self c'est la classe.
Pour corriger ces 2 problèmes, il suffit d'ajouter le
chapeau pour retourner une valeur bien particulière.
Problème suivant. Si ce code-là est exécuté, le
système semble être bloqué, il ne se passe plus rien et
impossible d'interagir avec Pharo.
D'où vient ce problème ?
Le problème vient du fait qu'on est en train d'implémenter
une méthode new dans dice classe.
Self c'est Dice,
et donc self new va se rappeler récursivement.
Ce qu'on a voulu faire ici, c'est utiliser l'initialisation,
la création d'instance par défaut définie dans la super
classe de Dice, et ensuite ajouter des choses par rapport à ça.
En l'écrivant comme ça, on a une boucle infinie.
Il faut remplacer self par super pour demander l'implémentation
de la super-classe.
Ce que vous devez retenir.
Donc on commet tous beaucoup d'erreurs.
Les erreurs que je vous ai présentées sont des erreurs
très, très fréquemment commises par tous les développeurs Pharo.
Il y a des choses qu'on retrouvent très régulièrement:
les points qui manquent, les parenthèses, le
chapeau qui manque ou yourself.
Essayez d'utiliser un maximum le débugger pour trouver l'origine
du problème. Vous verrez que le débugger vous aide
vraiment et qu'il ne vaut mieux pas le fermer dès qu'il
s'ouvre, parce que vous loupez une façon de corriger les problèmes.