I've had a couple of scripts which work fine in 8.6 but fail in 9.0 and
9.1 Below is a small program that exhibits this change of behaviour:
namespace eval GUI {
   variable x_counter 1
   proc create {} {
       puts "\tGUI::create => $GUI::x_counter"
   }
}
puts "Tcl patchlevel = [info patchlevel]"
puts "\tGUI exists = [namespace exists GUI]"
puts "\tGUI::x_counter exists = [info exists GUI::x_counter]"
puts "\tx_counter = $GUI::x_counter"
if {[catch {GUI::create} err]} {
   puts "\t***Error: $err"
} else {
   puts "\t*** Success ***"
}
Output:
Tcl patchlevel = 8.6.13
       GUI exists = 1
       GUI::x_counter exists = 1
       x_counter = 1
       GUI::create => 1
       *** Success ***
Tcl patchlevel = 9.0.0
       GUI exists = 1
       GUI::x_counter exists = 1
       x_counter = 1
       ***Error: can't read "GUI::x_counter": no such variable
Tcl patchlevel = 9.1a1
       GUI exists = 1
       GUI::x_counter exists = 1
       x_counter = 1
       ***Error: can't read "GUI::x_counter": no such variable
To me this looks like a bug since the variable exists and it'd be really strange for a variable to exist that causes a crash when used.
Thanks for any help.
Simon
Thanks for any help.
Simon
Dear Simon,
this is intended. You are using a miss-behaviour of 8.6, that it
searches a variable not starting with "::" in the global namespace, if
it is not found in the current namespace.
How it is IMHO intended, e.g. use a namespace locale variable:
namespace eval GUI {
     variable x_counter 1
     proc create {} {
         variable x_counter
         puts "\tGUI::create => $x_counter"
     }
}
What also works is full qualified namespaces:
namespace eval GUI {
     variable x_counter 1
     proc create {} {
         puts "\tGUI::create => $::GUI::x_counter"
     }
}
Why your own example worked:
namespace eval GUI { ;# create namespace
     variable x_counter 1 ;# create namespace local variable
     proc create {} { ;# create namespace locale procedure
         puts "\tGUI::create => $GUI::x_counter"
     }
}
The $GUI::x_counter specifies a variable in the namespace ::GUI::GUI Namespace and variable does not exist.
In 8.6, this was looked-up in the global namespace and found the
variable in namespace "::GUI".
Why this was an issue:
set x_counter 1
namespace eval GUI {
   set s_counter 1
}
would pic the global variable, if it exists and create otherwise a
namespace local variable. In consequence, it was not possible to create
a namespace variable with the same name as a global variable.
Hope this helps,
Harald
Am 22.03.2026 um 15:09 schrieb Simon Geard:
I've had a couple of scripts which work fine in 8.6 but fail in 9.0
and 9.1 Below is a small program that exhibits this change of behaviour:
namespace eval GUI {
    variable x_counter 1
    proc create {} {
        puts "\tGUI::create => $GUI::x_counter"
    }
}
puts "Tcl patchlevel = [info patchlevel]"
puts "\tGUI exists = [namespace exists GUI]"
puts "\tGUI::x_counter exists = [info exists GUI::x_counter]"
puts "\tx_counter = $GUI::x_counter"
if {[catch {GUI::create} err]} {
    puts "\t***Error: $err"
} else {
    puts "\t*** Success ***"
}
Output:
Tcl patchlevel = 8.6.13
        GUI exists = 1
        GUI::x_counter exists = 1
        x_counter = 1
        GUI::create => 1
        *** Success ***
Tcl patchlevel = 9.0.0
        GUI exists = 1
        GUI::x_counter exists = 1
        x_counter = 1
        ***Error: can't read "GUI::x_counter": no such variable
Tcl patchlevel = 9.1a1
        GUI exists = 1
        GUI::x_counter exists = 1
        x_counter = 1
        ***Error: can't read "GUI::x_counter": no such variable
To me this looks like a bug since the variable exists and it'd be
really strange for a variable to exist that causes a crash when used.
Thanks for any help.
Simon
Dear Simon,
this is intended. You are using a miss-behaviour of 8.6, that it
searches a variable not starting with "::" in the global namespace, if
it is not found in the current namespace.
Many years ago, when dealing over and over with this exact issue, I cameThanks for any help.
Simon
Dear Simon,
this is intended. You are using a miss-behaviour of 8.6, that it
searches a variable not starting with "::" in the global namespace, if
it is not found in the current namespace.
How it is IMHO intended, e.g. use a namespace locale variable:
namespace eval GUI {
variable x_counter 1
proc create {} {
variable x_counter
puts "\tGUI::create => $x_counter"
}
}
What also works is full qualified namespaces:
namespace eval GUI {
variable x_counter 1
proc create {} {
puts "\tGUI::create => $::GUI::x_counter"
}
}
Why your own example worked:
namespace eval GUI { ;# create namespace
variable x_counter 1 ;# create namespace local variable
proc create {} { ;# create namespace locale procedure
puts "\tGUI::create => $GUI::x_counter"
}
}
The $GUI::x_counter specifies a variable in the namespace ::GUI::GUI Namespace and variable does not exist.
In 8.6, this was looked-up in the global namespace and found the
variable in namespace "::GUI".
Why this was an issue:
set x_counter 1
namespace eval GUI {
set s_counter 1
}
would pic the global variable, if it exists and create otherwise a namespace local variable. In consequence, it was not possible to create
a namespace variable with the same name as a global variable.
Hope this helps,
Harald
Thank you, that indeed was the problem. The example I gave was my
attempt to distil the essence of a much larger tk app. The offending
lines there were of the form
ttk::entry $fr.e$i -textvariable GUI::x_letters($i)
trace add variable GUI::x_letters($i) write GUI::reset_order
I've now changed them all to
ttk::entry $fr.e$i -textvariable ::GUI::x_letters($i)
trace add variable GUI::x_letters($i) write ::GUI::reset_order
And all is okay. [namespace current]::x_letters($i) also works.
On Sun, 22 Mar 2026 20:17:00 +0000
Simon Geard <simon@whiteowl.co.uk> wrote:
Thank you, that indeed was the problem. The example I gave was myThanks for any help.
Simon
Dear Simon,
this is intended. You are using a miss-behaviour of 8.6, that it
searches a variable not starting with "::" in the global namespace, if
it is not found in the current namespace.
How it is IMHO intended, e.g. use a namespace locale variable:
namespace eval GUI {
     variable x_counter 1
     proc create {} {
         variable x_counter
         puts "\tGUI::create => $x_counter"
     }
}
What also works is full qualified namespaces:
namespace eval GUI {
     variable x_counter 1
     proc create {} {
         puts "\tGUI::create => $::GUI::x_counter"
     }
}
Why your own example worked:
namespace eval GUI { ;# create namespace
     variable x_counter 1 ;# create namespace local variable
     proc create {} { ;# create namespace locale procedure
         puts "\tGUI::create => $GUI::x_counter"
     }
}
The $GUI::x_counter specifies a variable in the namespace ::GUI::GUI
Namespace and variable does not exist.
In 8.6, this was looked-up in the global namespace and found the
variable in namespace "::GUI".
Why this was an issue:
set x_counter 1
namespace eval GUI {
   set s_counter 1
}
would pic the global variable, if it exists and create otherwise a
namespace local variable. In consequence, it was not possible to create
a namespace variable with the same name as a global variable.
Hope this helps,
Harald
attempt to distil the essence of a much larger tk app. The offending
lines there were of the form
ttk::entry $fr.e$i -textvariable GUI::x_letters($i)
trace add variable GUI::x_letters($i) write GUI::reset_order
I've now changed them all to
ttk::entry $fr.e$i -textvariable ::GUI::x_letters($i)
trace add variable GUI::x_letters($i) write ::GUI::reset_order
And all is okay. [namespace current]::x_letters($i) also works.
Many years ago, when dealing over and over with this exact issue, I came
to the conclusion that I needed some helper functions for both variable resolution (for -*variable options of widgets) and command resolution
(for callbacks) when working with Tk and namespaces.
My solution, which were wrappers for both [namespace which -command] and [namespace which -variable], was
###########################################################################
# build fully qualifiied command prefixes
proc fqcmd {cmd args} {
set fqcmd [uplevel 1 [list namespace which -command $cmd]]
if {$fqcmd eq ""} {
return -code error "unknown command \"$cmd\""
}
return [linsert $args 0 $fqcmd]
}
###########################################################################
# build fully qualified varnames
proc fqvar {name} {
set fqvar [uplevel 1 [list namespace which -variable $name]]
if {$fqvar eq ""} {
return -code error "unknown variable \"$name\""
}
return $fqvar
}
With these helper functions, working with Tk and namespaces is a breeze.
Just call
% ttk::entry $fr.e$i -textvariable [fqvar x_letters]($i) ;#[1]
or
% trace add variable [fqvar x_letters]($i) write [fqcmd reset_order]
to resolve both variables and callback commands from the current namespace. Even working with TclOO is immediate. If you want a callback to be a method of the current object, just call [fqcmd my $method ?arg ...?], or if you want a widget to use a variable from the current object use
[ttk::entry $parent.entry -textvariable [fqcmd $objvarname]].
The only shortcoming of this approach is that both variables and commands must already exists when the [fqvar]/[fqcmd] command is called. For me,
this has proven to be a non issue. I just define the required variables or procs before calling the GUI building code. This approach made the
transition from 8 to 9 virtually painless.
[1] The need to call [fqvar arrayname](element) instead of
[fqvar arrayname(element)] is due to bug#472113: https://core.tcl-lang.org/tcl/tktview/472113
| Sysop: | DaiTengu |
|---|---|
| Location: | Appleton, WI |
| Users: | 1,113 |
| Nodes: | 10 (0 / 10) |
| Uptime: | 492334:31:27 |
| Calls: | 14,238 |
| Files: | 186,312 |
| D/L today: |
3,268 files (1,061M bytes) |
| Messages: | 2,514,808 |