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 {
-a-a-a variable x_counter 1
-a-a-a proc create {} {
-a-a-a-a-a-a-a puts "\tGUI::create => $GUI::x_counter"
-a-a-a }
}
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]} {
-a-a-a puts "\t***Error: $err"
} else {
-a-a-a puts "\t*** Success ***"
}
Output:
Tcl patchlevel = 8.6.13
-a-a-a-a-a-a-a GUI exists = 1
-a-a-a-a-a-a-a GUI::x_counter exists = 1
-a-a-a-a-a-a-a x_counter = 1
-a-a-a-a-a-a-a GUI::create => 1
-a-a-a-a-a-a-a *** Success ***
Tcl patchlevel = 9.0.0
-a-a-a-a-a-a-a GUI exists = 1
-a-a-a-a-a-a-a GUI::x_counter exists = 1
-a-a-a-a-a-a-a x_counter = 1
-a-a-a-a-a-a-a ***Error: can't read "GUI::x_counter": no such variable
Tcl patchlevel = 9.1a1
-a-a-a-a-a-a-a GUI exists = 1
-a-a-a-a-a-a-a GUI::x_counter exists = 1
-a-a-a-a-a-a-a x_counter = 1
-a-a-a-a-a-a-a ***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
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 {
-a-a-a-a variable x_counter 1
-a-a-a-a proc create {} {
-a-a-a-a-a-a-a-a puts "\tGUI::create => $GUI::x_counter"
-a-a-a-a }
}
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]} {
-a-a-a-a puts "\t***Error: $err"
} else {
-a-a-a-a puts "\t*** Success ***"
}
Output:
Tcl patchlevel = 8.6.13
-a-a-a-a-a-a-a-a GUI exists = 1
-a-a-a-a-a-a-a-a GUI::x_counter exists = 1
-a-a-a-a-a-a-a-a x_counter = 1
-a-a-a-a-a-a-a-a GUI::create => 1
-a-a-a-a-a-a-a-a *** Success ***
Tcl patchlevel = 9.0.0
-a-a-a-a-a-a-a-a GUI exists = 1
-a-a-a-a-a-a-a-a GUI::x_counter exists = 1
-a-a-a-a-a-a-a-a x_counter = 1
-a-a-a-a-a-a-a-a ***Error: can't read "GUI::x_counter": no such variable
Tcl patchlevel = 9.1a1
-a-a-a-a-a-a-a-a GUI exists = 1
-a-a-a-a-a-a-a-a GUI::x_counter exists = 1
-a-a-a-a-a-a-a-a x_counter = 1
-a-a-a-a-a-a-a-a ***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 {
aaaaa variable x_counter 1
aaaaa proc create {} {
aaaaaaaaa variable x_counter
aaaaaaaaa puts "\tGUI::create => $x_counter"
aaaaa }
}
What also works is full qualified namespaces:
namespace eval GUI {
aaaaa variable x_counter 1
aaaaa proc create {} {
aaaaaaaaa puts "\tGUI::create => $::GUI::x_counter"
aaaaa }
}
Why your own example worked:
namespace eval GUI { ;# create namespace
aaaaa variable x_counter 1 ;# create namespace local variable
aaaaa proc create {} { ;# create namespace locale procedure
aaaaaaaaa puts "\tGUI::create => $GUI::x_counter"
aaaaa }
}
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 {
aaa 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 {
-a-a-a-a-a variable x_counter 1
-a-a-a-a-a proc create {} {
-a-a-a-a-a-a-a-a-a variable x_counter
-a-a-a-a-a-a-a-a-a puts "\tGUI::create => $x_counter"
-a-a-a-a-a }
}
What also works is full qualified namespaces:
namespace eval GUI {
-a-a-a-a-a variable x_counter 1
-a-a-a-a-a proc create {} {
-a-a-a-a-a-a-a-a-a puts "\tGUI::create => $::GUI::x_counter"
-a-a-a-a-a }
}
Why your own example worked:
namespace eval GUI { ;# create namespace
-a-a-a-a-a variable x_counter 1 ;# create namespace local variable
-a-a-a-a-a proc create {} { ;# create namespace locale procedure
-a-a-a-a-a-a-a-a-a puts "\tGUI::create => $GUI::x_counter"
-a-a-a-a-a }
}
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 {
-a-a-a 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: | Amessyroom |
|---|---|
| Location: | Fayetteville, NC |
| Users: | 65 |
| Nodes: | 6 (0 / 6) |
| Uptime: | 06:22:07 |
| Calls: | 862 |
| Files: | 1,311 |
| D/L today: |
921 files (14,318M bytes) |
| Messages: | 264,699 |