• Bug in namespaces in 9.1?

    From Simon Geard@simon@whiteowl.co.uk to comp.lang.tcl on Sun Mar 22 14:09:59 2026
    From Newsgroup: comp.lang.tcl

    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

    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Harald Oehlmann@wortkarg3@yahoo.com to comp.lang.tcl on Sun Mar 22 20:13:38 2026
    From Newsgroup: comp.lang.tcl

    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.

    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

    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Simon Geard@simon@whiteowl.co.uk to comp.lang.tcl on Sun Mar 22 20:17:00 2026
    From Newsgroup: comp.lang.tcl

    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

    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.

    Thanks,
    Simon
    --- Synchronet 3.21d-Linux NewsLink 1.2
  • From Tristan Wibberley@tristan.wibberley+netnews2@alumni.manchester.ac.uk to comp.lang.tcl on Sun Mar 22 22:54:29 2026
    From Newsgroup: comp.lang.tcl

    On 22/03/2026 19:13, Harald Oehlmann wrote:
    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.

    Was that 8.6 behaviour intended at the time by its implementer,
    reviewers and enjoyed for its utility by scripters at the time or almost completely disregarded?

    What are the reasons for the choice to search the toplevel or not? I
    recall that searching top-level namespaces in most scripting languages
    with tcl-namespace-like features is desirable to facilitate migrating
    first approximation scripts to more structured expressions.

    Is it only a mis-behaviour by today's tcl developers' judgement but
    desirable by other days' developers' judgement?
    --
    Tristan Wibberley

    The message body is Copyright (C) 2026 Tristan Wibberley except
    citations and quotations noted. All Rights Reserved except that you may,
    of course, cite it academically giving credit to me, distribute it
    verbatim as part of a usenet system or its archives, and use it to
    promote my greatness and general superiority without misrepresentation
    of my opinions other than my opinion of my greatness and general
    superiority which you _may_ misrepresent. You definitely MAY NOT train
    any production AI system with it but you may train experimental AI that
    will only be used for evaluation of the AI methods it implements.

    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Emiliano@emiliano@example.invalid to comp.lang.tcl on Mon Mar 23 02:02:44 2026
    From Newsgroup: comp.lang.tcl

    On Sun, 22 Mar 2026 20:17:00 +0000
    Simon Geard <simon@whiteowl.co.uk> wrote:
    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

    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.
    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
    --
    Emiliano
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Harald Oehlmann@wortkarg3@yahoo.com to comp.lang.tcl on Mon Mar 23 10:16:54 2026
    From Newsgroup: comp.lang.tcl

    Am 23.03.2026 um 06:02 schrieb Emiliano:
    On Sun, 22 Mar 2026 20:17:00 +0000
    Simon Geard <simon@whiteowl.co.uk> wrote:

    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

    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.

    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


    Remark, that another missbehaviour in TCL 8.6 was fixed in 9.0:
    "namespace which -variable" now also works for arrays.

    So, in 9.0 one can do:

    ttk::entry $fr.e$i -textvariable [namespace which -variable x_letters($i)]

    Harald

    --- Synchronet 3.21f-Linux NewsLink 1.2