EPOOL - Environnement de Programmation Orientée Objet en Lingo par Irv Kalb
Conventions de nommage
Bien que nous ayons à peine commencé, je voudrais faire une parenthèse rapide mais importante pour définir certains points utiles à l'ensemble du livre. Dans tous les exemple de code de ce livre, j'utiliserai une convention pour choisir le nom des variables et des gestionnaires. Une convention de nommage est un consensus entre programmeurs qui définit la façon de choisir les noms des variables et des gestionnaires à partir de quelques règles et conseils. Bien qu'un tel concept de convention de nommage n'est pas familier à de nombreux programmeurs Lingo, c'est une pratique très répandue depuis des années dans d'autres langages de programmation plus traditionnels.
Lorsqu'il code, un programmeur a la liberté dans le choix du nom des variables et des gestionnaires qu'il crée. Il peut décider d'utiliser des noms longs ou courts, parlants ou obscurs, utiles car décrivant leur fonction ou génériques. Cela dépend pour beaucoup de l'état d'esprit du codeur. Ce code est-il destiné à être réutilisé ? S'agit-il de code 'rapide et sale' ? Le code est-il si simple qu'il en est évident ? Les noms des variables et des gestionnaires peuvent se révéler très important dans la lisibilité du code. Le choix des noms des variables et gestionnaires peut paraître de second ordre, mais s'appliquer à choisir des noms parlants aide un programmeur à organiser sa pensée. Si vous ne parvenez pas à trouver un nom explicite pour une variable, alors il est probable que l'utilité de cette variable n'a pas encore été clairement établi. De même si vous ne trouvez aucun nom descriptif pour un gestionnaire, c'est peut-être que vous n'avez pas encore une idée suffisamment précise de sa fonction pour pouvoir déjà le coder.
En nommant d'une certaine manière vos variables et vos gestionnaires, vous pouvez incorporer beaucoup d'informations juste dans leur nom. La convention de nommage que j'utilise implique l'adoption d'une notation préfixée où les lettres du préfixe renseignent le lecteur sur la portée et le type de la variable.
Portée
La portée est la définition des portions de code d'où la variable est accessible. Accessible signifie que vous pouvez récupérer et définir sa valeur. Du point de vue de la portée, nous discernons trois types de variables en Lingo.
Le premier type de variable est la variable globale. Comme son nom l'indique, une variable globale est accessible de partout dans Director. Il vous suffit juste de faire une déclaration de globale définissant cette variable au début de chaque script dans lequel vous voulez manipuler cette variable globale.
Le second type de variable est la variable locale. La portée d'une variable locale commence avec sa première utilisation dans un gestionnaire jusqu'à la fin de ce gestionnaire. Aucune déclaration préalable n'est nécessaire avec ce genre de variables. Lingo crée un espace mémoire à la première utilisation de la variable locale lors de son utilisation dans un gestionnaire, puis libère cet espace mémoire à la fin du gestionnaire.
Enfin nous trouvons les propriétés qui sont déclarées et utilisées dans les scripts parents. La portée d'une propriété la rend accessible de l'ensemble du script courant. Les propriétés sont l'élément essentiel qui permet aux objets de stocker des informations. Lorsque vous déclarez une propriété dans un script parent, cette variable est accessible à toutes les méthodes de ce script parent. Ainsi les différentes méthodes de votre objet peuvent manipuler les mêmes données. Si vous définissez la valeur d'une propriété dans une méthode, la propriété va conserver cette valeur et les autres méthodes de votre objet peuvent lire ou redéfinir sa valeur. Comme nous l'avons vu dans le premier chapitre, vous définissez une propriété en utilisant le mot-clé "property" suivi du nom de votre variable. Par exemple :
property pCompteur
(Note: Les propriétés fonctionnent de la même manière dans les comportements.)
Avec ma convention de nommage, la première lettre nous renseigne sur la portée de la variable. Les noms des variables globales commencent par un "g" minuscule. Par exemple gCompteur, gChemin, etc. Les noms de toutes les propriétés débutent par un "p" minuscule. C'est pourquoi dans l'exemple précédent j'ai choisi de nommer ainsi pCompteur. Le "p" nous dit qu'il s'agit d'une propriété. Le nom d'une variable locale commence par n'importe quelle lettre minuscule, à l'exception de "g" et de "p". Comme variable locale nous pouvons dès lors utiliser i, j, temp, unNombre, uneValeur, etc.
Type
Dans un langage de programmation, les données sont contenues dans des variables. Mais ces données sont de différents types, par exemple des entiers, des nombres à virgule flottante, des chaînes, des listes, etc. Dans de nombreux langages de programmation vous devez préciser de manière explicite le type de variable lors de sa déclaration.
// *** exemple en C
int x;
string y;
float z;
// ***
En FORTRAN, les variables ne pouvaient représenter que des entiers ou des réels. Le compilateur avait besoin d'un moyen de différencier ces deux types. Lors de la création du langage, il avait été décidé que le type de variable serait déterminé par la première lettre du nom de la variable. Chaque variable dont le nom commençait par une lettre comprise entre I et N représentait un entier, et les autres noms commençant par une lettre hors de cet intervalle désignaient un nombre réel (un nombre flottant). I et N ont été choisies pour déterminer l'intervalle car il s'agit des deux premières lettres du mot entier (integer). FORTRAN imposait donc sa convention de nommage aux programmeurs par sa conception.
En Lingo nous n'avons pas de telles restrictions. Par opposition au Fortran, Lingo n'est pas un langage typé. Le créateur du Lingo (John Thompson) a dit qu'il était très fier que n'importe quelle variable Lingo puisse contenir n'importe quelle donnée. Cette caractéristique rend Lingo très souple. Par exemple avec la déclaration suivante :
x = 4
Non seulement la valeur de la variable x est définie à 4, mais le type de la variable est aussi défini comme entier. Nous pouvons utiliser la fonction ilk() pour connaître le type d'une variable :
put ilk(x)
--#integer
Cependant il nous suffit de redéfinir la valeur de la même variable pour modifier aussi son type :
x = 5.0
put ilk(x)
-- #float
x = "abc"
put ilk(x)
-- #string
Puisqu'une variable Lingo peut représenter n'importe quel type de données, il serait intéressant de trouver un moyen quelconque pour préciser le type de variable à partir de son nom. Voici le prochain aspect de la convention de nommage. Juste après la lettre "g" pour les globales ou "p" pour les propriétés, nous pouvons placer une ou plusieurs lettres pour indiquer le type de données manipulées au travers de cette variable. Voici une liste des préfixes que j'utilise souvent, accompagnés des types de données Lingo qu'ils représentent :
| f | flag/booléen (TRUE ou FALSE) | |
| l | liste | |
| ch | channel / piste | |
| m | member / acteur | |
| k | constante | |
| o | objet (nous y reviendrons en détail dans le chapitre suivant, pour l'instant il suffit de constater qu'il est intégré dans la convention de nommage) |
A quoi s'ajoute une lettre bien pratique :
| n | nombre |
Par combinaison, nous avons accès à des types de données plus complexes :
| nm | nombre d'acteurs | |
| lf | lie de booléens | |
| lch | liste de pistes |
Radical du nom de variable
Après les préfixes de portée et de type arrive le vrai nom de la variable. Les variables sont en quelque sorte les "noms" d'un langage de programmation - nous les utilisons pour décrire les choses que le langage manipule. Du point de vue de Lingo, le nom de la variable n'a aucune signification particulière - chaque nom fonctionne comme n'importe quel autre. Une variable appelée "x" pourrait tout aussi bien être appelée "sommesNousConnectesAInternet". Pourtant l'utilisation de noms de variable parlants peut faire la différence, en particulier pour les programmeurs qui doivent travailler sur du code dont ils ne sont pas les auteurs. Du point de vue de la compréhension humaine du code, il est sensé d'utiliser des noms de variables aussi descriptifs que possible. Ainsi quand vous, ou à plus forte raison un autre développeur, essaierez de relire du code longtemps après son écriture, celui-ci sera encore clair et compréhensible.
La règle de syntaxe du radical du nom de la variable : utilisez un ou plusieurs mots en n'utilisant les majuscules que pour la première lettre de chaque mot.
La seule exception à cette règle est le cas d'une variable très locale dont le nom ne contient alors pas d'information de type. Par exemple j'utilise souvent la variable "i" comme compteur dans une boucle telle que : repeat with i = 1 to 10. Un autre exemple peut être une déclaration simple comme : coutTotal = nObjets * prix . Remarquez toutefois que tous les noms de variables commencent par une minuscule.
Exemple de noms de variables complets
Voici quelques exemples de noms de variables qui respectent cette convention de nommage, accompagnés de leur signification :
| gkSliderTop | constante globale du sommet d'un slider | |
| goNavigation | objet global de navigation | |
| pchBouton | propriété, piste qui contient un bouton | |
| plNames | propriété qui désigne une liste de noms | |
| pnSceneMarkers | propriété qui contient le nombre de marqueurs de la scène | |
| ploAnimations | propriété qui désigne une liste d'objets Animation | |
| fOK | booléen local | |
| oScroller | objet local scroller | |
| lchBoutons | liste locale des pistes de boutons | |
| nmRoll | nombre local de l'acteur Roll |
| J'ai été initié au concept de convention de nommage il y a plusieurs années lorsque je travaillais pour Convergent Technologies. Il y a avait de nombreux programmeurs codant dans un langage appelé PL/M. Avec les changements de tâches, il était important de comprendre et maîtriser le code des autres programmeurs rapidement. Certains des anciens programmeurs avaient travaillé avec un homme nommé Charles Simonyi au Xerox PARC (Palo Alto Research Center). M. Simonyi, qui descendait d'une famille hongroise, avait développé un style de nommage à base de préfixes. Ce style a ensuite était appelé "notation hongroise". |
Les noms des gestionnaires
Si les variables sont les noms d'un langage, alors les gestionnaires en sont les "verbes" - ils spécifient les actions. Encore une fois il paraît intelligent d'essayer d'utiliser des noms aussi parlants que possible qui décrivent l'action. Pour le choix des noms des gestionnaires j'utilise quelques règles très simples. Chaque gestionnaire accessible globalement commence par une lettre majuscule. Si le nom comporte plus d'un mot, alors chaque mot commence par une majuscule. Tous les gestionnaires qui sont des méthodes d'un objet commencent par un "m" minuscule. Voici quelques exemples :
StartSound("SoundName") -- appelle un gestionnaire de son global
ImprimerDesPages(lPagesAImprimer, fAvecEnTete) -- appelle un gestionnaire global d'impression
numeroPageSuivante = mTrouvePageSuivante(oPage, numPageCourante) -- appelle la méthode mTrouvePageSuivante de l'objet oPage
mSetPuppets(me, TRUE) -- appelle une méthode interne à l'objet
L'utilité d'une convention de nommage
Voici un extrait du code d'un script parent que je vais utiliser pour démontrer l'intérêt d'une convention de nommage. Il s'agit de trois variantes du même code. Les trois exemples produisent les mêmes actions de la même façon. La seule différence se situe au niveau des noms des variables et des gestionnaires.
Vous allez peut-être trouver ce premier extrait à peu près illisible (c'est ce que j'en penserai à votre place). Les noms des variables et des gestionnaires ne donnent aucune idée de ce qu'ils représentent (C'est épouvantable mais vrai - on trouve beaucoup de code dans le monde réel qui ressemble à ça.)
global
d
global r
global c
on unEvenement
if count(r) = 0 then
s()
end if
x = FALSE
b = count(r)
repeat while
NOT(x)
i = random(b)
n = getAt(r, i)
if n <> c then
x = TRUE
c = n
end if
end repeat
deleteAt(r, I)
if d then
put ("La réponse est:"
&& n)
end if
return n
end
La deuxième version apporte du sens dans les noms des variables et des gestionnaires. Cependant vous remarquerez que les noms ne vous donnent pas d'information sur le type de donnée qu'ils représentent, ni sur la portée. Ici c'est un choix de placer les déclarations globales juste avant le gestionnaire. Si ce script comportait plusieurs gestionnaires et que nous ne nous intéressions qu'à celui-ci en particulier, il serait aisé de passer à côté des déclarations globales. Dans ce cas, il aurait été malaisé de trouver quelles variables étaient locales et lesquelles étaient globales.
global
debug
global disponible
global numeroprecedent
on getrandomsuivant
if count(disponible)
= 0 then
initlist()
end if
done = FALSE
n = count(disponible)
repeat while NOT(done)
randomindex = random(n)
randomnum = getAt(disponible,
randomindex)
if randomnum <> numeroprecedent
then
done = TRUE
numeroprecedent
= randomnum
end if
end repeat
deleteAt(disponible,
randomindex)
if debug then
put ("La réponse est:"
&& randomnum)
end if
return randomnum
end getrandomsuivant
Enfin voici le même code, qui cette fois respecte nos conventions de nommage. En lisant le code la portée des variables est explicite. Il devient aussi évident de différencier les listes des booléens ou des entiers.
global
gfDebug
global glDisponnible
global gNumeroPrecedent
on GetRandomSuivant
if count(glDisponnible)
= 0 then
InitList()
end if
fTermine = FALSE
nDisponible = count(glDisponnible)
repeat while NOT(fTermine)
randomIndex = random(nDisponible)
randomNum = getAt(glDisponnible,
randomIndex)
if randomNum <> gNumeroPrecedent
then
fTermine
= TRUE
gNumeroPrecedent
= randomNum
end if
end repeat
deleteAt(glDisponnible,
randomIndex)
if gfDebug then
put ("La réponse est:"
&& randomNum)
end if
return randomNum
end mGetRandomSuivant
Bien que l'utilisation d'un telle convention puisse sembler ajouter beaucoup de travail, c'est quelque chose qui en vaut largement la peine. Après un moment cela devient un réflexe. En fait cela vous oblige à vous arrêter et à réfléchir sur ce que devrait être le nom "correct" de la variable ou du gestionnaire. Le gain se fait sentir lorsque vous essayez de relire du code que vous avez écrit précédemment. Si vous avez oublié le fonctionnement de certaines portions de code, vous serez surpris de voir combien il est aisé de comprendre comment marche du code qui suit ces conventions. Cela vous sera encore plus utile si vous faites partie d'une équipe qui a adopté ces conventions. Vous découvrirez que l'utilisation de ces conventions vous permet de comprendre le code de vos collaborateurs bien plus vite que si aucune convention n'avait été utilisée.
Même si vous choisissez de ne pas utiliser des conventions aussi complète que celle que je viens de décrire, l'utilisation minimum de "g" pour les globales et de "p" pour les propriétés améliorera la lisibilité de votre code Lingo.