16/01/2011, 00:21
(Modification du message : 16/01/2011, 01:03 par MenzAgitat.)
Voici un problème que vous pouvez avoir rencontré sans le comprendre ou sans vous en apercevoir.
Il est susceptible de créer des conflits de variables entre plusieurs scripts, mais peut aussi bien n'avoir aucune conséquence visible bien qu'étant quand même là.
Commençons par créer un array nommé testvar dans le namespace global.
tcl
.tcl array set testvar {1 a 2 b}
Tcl:
Nous allons maintenant tenter de créer une variable du même nom dans la déclaration du namespace testnamespace.
tcl
.tcl namespace eval ::testnamespace { set testvar 1 }
Tcl error: can't set "testvar": variable is array
Plutôt curieux, on a tenté de créer la variable testvar depuis l'intérieur du namespace testnamespace mais il semble que Tcl veuille la créer dans le namespace global à la place. Par conséquent, nous obtenons une erreur car on ne peut pas redéfinir une variable de type array de cette façon.
Reproduisons maintenant le test mais en incluant le code dans une procédure.
tcl
.tcl namespace eval ::testnamespace { proc testproc {} { set testvar 1 } }
Tcl:
puis exécutons ladite procédure
tcl
.tcl ::testnamespace::testproc
Tcl: 1
Là, plus d'erreur
tcl
.tcl info exists ::testnamespace::testvar
Tcl: 0
On peut constater accessoirement que la variable n'existe déjà plus.
En effet, set utilisé dans une procédure crée une variable temporaire... à moins qu'elle n'ait été déclarée par variable auparavant :
tcl
.tcl namespace eval ::testnamespace { proc testproc {} { variable testvar ; set testvar 1 } }
Tcl:
ou plus simplement
tcl
.tcl namespace eval ::testnamespace { proc testproc {} { variable testvar 1 } }
Tcl:
.tcl ::testnamespace::testproc
Tcl:
.tcl info exists ::testnamespace::testvar
Tcl: 1
_____________________
Que conclure de tout ça ?
Le seul cas où vous devriez utiliser namespace eval est pour "déclarer" le namespace et initialiser vos variables au moyen de la commande variable.
En dehors de ces variables proprement déclarées, il est plus sûr de définir vos autres variables en dehors du namespace eval (juste au cas où il existerait une variable globale du même nom).
Il faut savoir que lorsque vous définissez une variable au moyen de set sans l'avoir au préalable déclarée avec variable, Tcl recherche la variable dans le namespace local, ne la trouve pas (puisqu'elle n'est pas déclarée), puis décide qu'il s'agit d'une variable globale (située dans le namespace global).
Par conséquent, ce n'est pas la variable $testnamespace::testvar qui est créée, mais bien $::testvar.
Pour éviter d'"égarer" vos variables dans le namespace global et ainsi risquer un conflit avec une autre variable qui porterait le même nom, voici la bonne façon de procéder :
tcl
.tcl namespace eval ::testnamespace { variable testvar }
Tcl:
.tcl proc ::testnamespace::testproc {} { set testvar 1 }
Tcl:
.tcl ::testnamespace::testproc
Tcl: 1
Une bonne habitude à prendre est de définir et d'appeler vos variables en précisant systématiquement leur namespace, ça élimine tout risque de confusion. L'exemple qui suit peut donc se passer de l'initialisation de la variable :
tcl
.tcl namespace eval testnamespace {}
Tcl:
.tcl set ::testnamespace::testvar 1
Tcl: 1
.tcl info exists ::testnamespace::testvar
Tcl: 1
Voici qui peut être pratique pour traquer la création de variables globales, et donc détecter d'éventuels problèmes de "fuites" de variables dans un script : Watching Global Variables Creation for Memory Leak Detection
Source : Namespace confusion