Quelques "namespace"ries

 

XG - Un pense bête sur les pièges des namespaces, à commenter


Un namespace simple ...

 % namespace eval A {
    set Var1 plop
    proc updateVar1 {} {
        set A::Var1 taadaa
    }
    proc creeVar2 {} {
        set A::Var2 polom
    }
    proc creeVraimentVar2 {} {
        set [namespace current]::Var2 polomVraiment
    }
    alias updateVar2_1 creeVar2
    alias [namespace current]::updateVar2_2 [namespace current]::creeVar2
 }

Utilisons ça simplement ...

 % puts $::A::Var1
 plop

 % ::A::updateVar1
 taadaa

 % puts $::A::Var1
 taadaa

 % puts $::A::Var2
 can't read "::A::Var2": no such variable

 % ::A::creeVar2
 can't set "A::Var2": parent namespace doesn't exist

 % puts $::A::Var2
 can't read "::A::Var2": no such variable

 % ::A::creeVraimentVar2
 polomVraiment

 % puts $::A::Var2
 polomVraiment

 % ::A::updateVar2_1
 invalid command name "::A::updateVar2_1"

 % ::A::updateVar2_2
 polom

ulis Elémentaire mon cher Xavier ! ;-)

Bin non. Pas vraiment.


1 - Il faut savoir que la résolution des noms de variables dans un namespace est contre-intuitive :

Tcl recherche d'abord dans le namespace courant, puis dans le namespace global.

Et crée dans le namespace global s'il n'a pas trouvé de variable dans le namespace courant.

Petit exemple :

  set var ma-globale
  namespace eval ::myspace \
  {
    set var mon-space
  }

  puts $var

->mon-space

  catch { puts $::myspace::var } msg
  puts $msg

->can't read "::myspace::var": no such variable

Moralité : toujours utiliser variable avant set ou array set pour créer la variable dans le namespace.

  set var globale
  namespace eval ::myspace \
  {
    variable var
    set var namespace
  }

2- Une procédure d'un namespace s'exécute dans son contexte de définition (c'est à dire son namespace)

Dans la procédure creeVar2 rajoute donc la ligne

  puts [namespace current]

Tu verras que la procédure s'exécute dans ::A.

Et donc que, avec A::Var2, tu essayes de créer Var2 dans ::A::A qui est un namespace qui n'existe pas.

Tu peux le créer juste avant avec

  namespace eval A {}

et vérifier que cette fois tu peux créer la variable (et qu'elle est bien dans ::A::A).

Moralité : toujours qualifier pleinement les namespaces avec ::

  namespace eval ::A {}
  set ::A::Var1 tugudu

Je te conseille d'oublier les autres petites chose (genre namespace code et autres ou de le faire après moult expérimentations)