Previous section   Next section

Practical Programming in Tcl & Tk, Third Edition
By Brent B. Welch

Table of Contents
Chapter 14.  Namespaces

Callbacks and Namespaces


Commands like after, bind, and button take arguments that are Tcl scripts that are evaluated later. These callback commands execute later in the global scope by default. If you want a callback to be evaluated in a particular namespace, you can construct the callback with namespace code. This command does not execute the callback. Instead, it generates a Tcl command that will execute in the current namespace scope when it is evaluated later. For example, suppose ::current is the current namespace. The namespace code command determines the current scope and adds that to the namespace inscope command it generates:

set callback [namespace code {set x 1}]
=> namespace inscope ::current {set x 1}
# sometime later ...
eval $callback

When you evaluate $callback later, it executes in the ::current namespace because of the namespace inscope command. In particular, if there is a namespace variable ::current::x, then that variable is modified. An alternative to using namespace code is to name the variable with a qualified name:

set callback {set ::current::x 1}

The drawback of this approach is that it makes it tedious to move the code to a different namespace.

If you need substitutions to occur on the command when you define it, use list to construct it. Using list is discussed in more detail on pages 123 and 389. Example 14-4 wraps up the list and the namespace inscope into the code procedure, which is handy because you almost always want to use list when constructing callbacks. The uplevel in code ensures that the correct namespace is captured; you can use code anywhere:

Example 14-4 The code procedure to wrap callbacks.
proc code {args} {
   set namespace [uplevel {namespace current}]
   return [list namespace inscope $namespace $args]
namespace eval foo {
   variable y "y value" x {}
   set callback [code set x $y]
   => namespace inscope ::foo {set x {y value}}

The example defines a callback that will set ::foo::x to y value. If you want to set x to the value that y has at the time of the callback, then you do not want to do any substitutions. In that case, the original namespace code is what you want:

set callback [namespace code {set x $y}]
=> namespace inscope ::foo {set x $y}

If the callback has additional arguments added by the caller, namespace inscope correctly adds them. For example, the scrollbar protocol described on page 431 adds parameters to the callback that controls a scrollbar.

      Previous section   Next section