4.3.4 les symboles

Toute séquence de caractères, soit une chaîne de caractères, soit un identifieur, précédée par le caractère # est un symbole. Ainsi #’une chaîne de caractères’ et #UneChaineDeCaractères sont des symboles. Les symboles sont des instances de la classe Symbol, une sous-classe de la classe String.


FIG. 4.5: La création d’un Symbol à partir de deux instances de String par le message asSymbol


Les symboles se distinguent des chaînes de caractères ordinaires par le fait qu’ils sont uniques, c’est-à-dire: dans un système SMALLTALK il ne peut pas avoir, à un instant donné, deux symboles différents portant le même nom. Autrement dit: deux occurences d’un même nom de symbole désignent la même instance de la classe Symbol. Par contre, si nous avons deux occurences d’une chaîne de caractères composées de la même séquence de caractères, nous ne pouvons pas, a priori, savoir si les deux chaînes sont identiques ou juste égales, si elles réfèrent à la même instance de la classe String ou pas.

Afin d’illustrer cette unicité des symboles, sachons que toute chaîne comprend le message asSymbol qui construit un symbole composé de la même suite de caractères que la chaîne receveur de ce message. Si nous transmettons à deux instances différentes de la classe String, composées de la même suite de caractères, le message asSymbol, le résultat sera un seul et même symbole. La figure 4.5 montre graphiquement ce résultat à partir de deux chaînes, composées toutes les deux des caractères $b, $a et $r, et dont la réponse au message asSymbol livre le même symbole #bar

Le sélecteur utilisé pour tester l’égalité est «=». Deux chaînes de caractères composées de la même séquence de caractères sont égales. Par exemple la transmission ’foo’ = ’foo’ retourne toujours true. Naturellement, deux symboles du même nom, puisqu’ils ne font qu’un unique symbole, sont égaux aussi, ainsi #foo = #foo retourne également toujours true.

Le sélecteur SQUEAK pour tester l’identité entre deux objets est «==». Deux symboles de même nom sont toujours identiques; ainsi #foo == #foo retourne toujours true. Par contre, bien que la chaîne ’foo’ et la chaîne ’foo’ copy soient des chaînes égales, elles sont garantie de ne pas être identiques et ’foo’ == ’foo’ copy retourne toujours false.

En SMALLTALK, identité veut toujours dire: même instance. Sauf pour les symboles, ce n’est pas toujours simple de savoir si deux objets sont identiques. Ainsi, deux petits entiers (instances de la classe SmallInteger) égaux sont (pour des raisons d’efficacité dans l’implémentation de SMALLTALK) toujours identiques. Par contre, il n’y a aucune raison que la fraction (1/4) soit identique à une autre occurence de la fraction (1/4). Le programmeur peut garantir l’identité, s’il contrôle lui-même le suivi de pointeurs. Ainsi

(1/4) == (1/4)
retourne false. Par contre, l’évaluation de l’expression:
|x y| x := 1/4. y := x. x == y31
retourne true, puisque les variables x et y désignent (sont liées à) la même instance de la classe Fraction.

SMALLTALK a besoin de cette charactéristique d’unicité des symboles, puisqu’il les utilise pour les noms de classes: s’il avait deux classes différentes du même nom, comment SMALLTALK saurait-il, et nous, les lecteurs de programmes SMALLTALK, saurions-nous, quelle classe est visée à un certain instant? Les sélecteurs de méthodes sont également des symboles. Ainsi #+, notre sélecteur pour faire des additions d’objets les plus divers, est un unique symbole pour une raison similaire à celle des symboles représentant des noms de classes: pour pouvoir hériter une méthode d’une de ses sur-classes, il faut bien que chaque classe contenant ce sélecteur le représente par un symbole identique, cela accélère grandement sa recherche. C’est cela aussi qui explique pourquoi, si l’on écrit:

(x < y) ifTrue: [...] ifFalse: [...]
le sélecteur du message est le symbole #ifTrue:ifFalse:, c’est-à-dire: la concatenation des parties constantes de toutes les transmissions de ce type.32 Naturellement, pour encore les mêmes raisons: l’objet receveur peut être soit true – seule et unique instance de la classe True – soit false – seule et unique instance de la classe False –, ces deux classes au moins doivent donc comprendre le même sélecteur. Si c’est le même symbole, il n’y a pas beaucoup de recherches à faire pour trouver la méthode associée.

Nous avons déjà rencontré des symboles. Réregardez la figure 4.2, page 182, qui montrait un extrait du dictionnaire système Smalltalk: toutes les variables et classes qui s’y trouvent sont des symboles!

Notons que l’écriture ordinaire d’un symbole, c’est-à-dire sans utiliser les caractères délimiteurs de chaîne de caractères, impose quelques restrictions sur les caractères permis. Pour des raisons de l’analyse syntaxique, un symbole, disons ordinaire, ne peut pas commencer par un nombre, et les seuls symboles qui commencent par des caractères spéciaux permis, les caractères «+-/*\~<=>@%|&?!», doivent être limités à un ou deux caractères. Ils correspondent aux sélecteurs binaires.33 Donc, #4oeufs, #" ou encore #!aha! ne sont pas des symboles. Par contre #’4oeufs’, #’"’ ou encore #’!aha!’ sont des symboles. La meilleure stratégie, quand vous devez créer des symboles, est de toujours commencer par un caractère alphabétique et de s’abstenir autant que possible d’utiliser des caractères spéciaux. Dans les très rares cas où il vous semble impossible d’éviter des caractères spéciaux, écrivez alors le nom entier entre deux apostrophes, les caractères délimiteurs de chaînes.