IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Cours complet pour apprendre à programmer en D


précédentsommairesuivant

25. Espace de nom (name space)

Tout nom est accessible depuis l'endroit où il a été défini jusqu'à l'endroit où l'on quitte sa portée, de même que dans toutes les portées que la sienne inclut. De ce point de vue, toute portée définit un espace de noms.

Les noms ne sont plus disponibles une fois que l'on a quitté leur portée :

 
Sélectionnez
void main()
{
   int dehors;
 
   if (uneCondition) {   // ← les accolades commencent une nouvelle portée
      int dedans = 1;
      dehors = 2;        // ← ça marche ; 'dehors' est défini à cet endroit
 
   } // ← 'dedans' n'est plus disponible au-delà de cet endroit
 
   dedans = 3;   // ← ERREUR de compilation
                 //   'dedans' n'est pas disponible dans la portée extérieure.
}

Parce que dedans est défini dans la portée de la condition if, elle est disponible seulement dans cette portée. En revanche, outer est disponible et dans la portée globale et dans la portée intérieure.

Définir le même nom dans une portée intérieure n'est pas autorisé :

 
Sélectionnez
size_t taille = nombresImpairs.length;
 
if (uneCondition) {
   size_t taille = nombresPremiers.length; // ← ERREUR de compilation
}

25-1. Définir les noms le plus proche possible de leur première utilisation

Comme nous l'avons fait dans tous les programmes jusqu'à maintenant, les variables doivent être définies avant leur première utilisation :

 
Sélectionnez
writeln(nombre);   // ← ERREUR de compilation
                   //   nombre n'est pas encore connu
int nombre = 42;

Pour que ce code soit acceptable par le compilateur, nombre doit être défini avant d'être utilisé avec writeln. Même s'il n'y a pas de restriction sur combien de lignes avant il devrait être défini, une bonne pratique de programmation est de définir les variables le plus près possible de là où elles sont utilisées pour la première fois.

Voyons ceci dans un programme qui affiche la moyenne des nombres qu'il demande à l'utilisateur. Les programmeurs qui ont l'habitude d'utiliser d'autres langages de programmation peuvent être accoutumés à définir les variables au début des portées :

 
Sélectionnez
int nombre;                               // ← ici
int[] nombres;                            // ← ici
double valeurMoyenne;                     // ← ici
 
write("Combien y a-t-il de nombres ? ");
 
readf(" %s", &nombre);
 
if (nombre >= 1) {
   nombres.length = nombre;
 
   // ... Supposons que le calcul se fasse ici ...
 
} else {
   writeln("ERREUR : Vous devez rentrer au moins un nombre !");
}

Comparez le code ci-avant avec celui qui suit et qui définit les variables plus tard, quand elles commencent à jouer un rôle dans le programme :

 
Sélectionnez
write("Combien y a-t-il de nombres ? ");
 
int nombre;                              // ← ici
readf(" %s", &nombre);
 
if (nombre >= 1) {
   int[] nombres;                        // ← ici
   nombres.length = nombre;
 
   double valeurMoyenne;                 // ← ici
 
   // ... supposons qu'il y a des calculs ici ...
 
} else {
   writeln("ERREUR : vous devez entrer au moins un nombre !");
}

Même si définir toutes les variables au début peut sembler mieux au niveau de la structure, il y a plusieurs avantages à les définir le plus tard possible.

  • Vitesse : chaque définition de variable a un coût en vitesse dans le programme. Comme toutes les variables sont initialisées à 0, définir les variables au début entraînerait potentiellement une initialisation coûteuse et inutile si ces variables n'étaient pas utilisées plus tard.
  • Risque d'erreurs : chaque ligne qui est entre la définition et l'utilisation d'une variable entraîne un risque plus grand de faire des erreurs de programmation. Pour prendre un exemple, considérez une variable portant un nom aussi commun que « taille ». Il est possible d'utiliser cette variable par inadvertance pour une autre taille avant de l'utiliser réellement pour ce pour quoi elle a été définie. Au moment où la ligne de son utilisation prévue est atteinte, la variable peut avoir une valeur non attendue.
  • Lisibilité : quand le nombre de lignes dans une portée est devenu grand, il est probable que la définition d'une variable peut être trop loin dans le code source, forçant le programmeur à faire défiler le code pour trouver cette définition.
  • Maintenance du code : le code source est modifié et amélioré constamment : de nouvelles fonctionnalités sont ajoutées, d'anciennes fonctionnalités sont supprimées, les bogues sont corrigés, etc. Ces modifications rendent parfois nécessaire le déplacement d'un groupe de lignes dans une nouvelle fonction.
    Quand cela arrive, avoir toutes les variables définies près des lignes qui les utilisent rend plus facile le déplacement de celles-ci comme un groupe cohérent.
    Par exemple, dans le code précédent, toutes les lignes dans le bloc if peuvent être déplacées dans une nouvelle fonction. Au contraire, quand les variables sont toujours définies au début, si les lignes doivent être déplacées, les variables qui sont utilisées dans ces lignes doivent être identifiées une à une.

précédentsommairesuivant