Updated 2018-06-16 13:58:27 by earnie

variable, a built-in Tcl command since 8.0, creates and optionally sets variables in a namespace.

See Also  edit

set
Reads or assigns a value to a variable.
namespace upvar
Gives a variable in one namespace a name in another.
upvar
Gives a variable at one level of evaluation a name in another.
Variables in TclOO
Discusses variable, oo::define variable, oo::objdefine variable and my variable in TclOO

Synopsis  edit

variable ?name value...? name ?value?

Documentation  edit

official reference

Description  edit

Creates a variable named by the tail of name, which may be fully-qualified , partially-qualified, or unqualified, it doesn't already exist. If a corresponding value is provided, the variable is set to that value.
namespace eval one {
    variable greeting hello
}
set one::greeting ;#-> hello

A variable may exist but be unset:
namespace which -variable hello; #-> ::hello
namespace which -variable goodbye; #-> <the empty string}

In a procedure, variable makes a variable named name available within the procedure as the of name.
proc p1 {} {
    variable name Priam 
}
p1 ;#-> Priam

namespace eval n1 {
    variable name Hector 
}
namespace eval n2 {
    proc p2 {} {
        variable ::n1::name
                set name
    }
}
n2::p2 ;#-> hector

To access a namespace variable from inside a procedure, declare it using variable. In this way variable resembles global, but global is restricted to variables in the global namespace.

name can refer to an array, but not to a variable in the array. Therefore, when name refers to an array, value must not be used. This implies that each array must be declared by a separate invocation of variable.

After an array variable has been created, member variables within the array using set or array.

variable provides all the functionality of global. Replacing global with variable within a procedure is often all that's needed when moving a procedure from the global namespace to another namespace. In contrast with global, the syntax of variable sometimes makes it necessary to have a sequence of variable commands within a procedure. To replace
global foo bar grill

requires
variable foo; variable bar; variable grill

RS: But the fewer globals you use, the better anyway ;-)

An Asymmetry with namespace which  edit

In the following example, namespace which identifies ::bar::a, but within foo::p1, variable resolves to ::foo::bar::a, which doesn't exist:
namespace eval ::bar {variable a 1}
namespace eval ::foo {
    puts [list {bar::a resolves to} [namespace which -variable bar::a]]
    proc p1 {} {
        variable bar::a
        puts $a
    }
}

namespace which -variable looks up variables in the same way that set does, whereas variable resolves a name relative to the current namespace, without looking to the global namespace like set may do.

Discussion  edit

escargo 2003-09-04: In URL behaviour in a text widget, there are some code idioms I am not familiar with. One of them is:
variable {}

What the heck is that supposed to do?

DGP: Just what the docs say. It creates a local variable whose name is the empty string within the procedure and links it to the namespace variable named [namespace current]::. Note that namespace tail [namespace current]:: is the empty string.

In this particular case, the variable named the empty string is an array variable, so one can set and read its member variables like so:
set (elem1) 1
set (elem2) 2
if {$(elem1) > $(elem2)} {
    set greater elem1
} else {
    set greater elem2
}
puts "Greater is $($greater)"

escargo 2003-09-05: Gosh wow. Not only is everything is a string, but nothing is a string. RS: 'Everything' includes 'nothing'...

KJN: 2004-08-12: I came here looking for an explanation of this unusual idiom, and I'm pleased to find it!

I had not realised until now that the minimum number of characters in a name is zero! (Is that mentioned in the manual anywhere?) Even without a variable statement, it is valid to write
set {} 12
puts ${}
set {}

This code will echo 12 to stdout, and return the value 12.

The empty string is an acceptable name for a proc:
proc {} a {
    puts $a
    return $a
}

{} 42

which echoes 42 to stdout and returns 42.

RS: For scalar variables and commands you still have to delimit the "nothing" with quotes or braces, but with array names, nothing is enough. The Tcl documentation says:
$''name''(index) 

name is the name of an array variable and index is the name of an element within that array. Name must contain only letters, digits, underscores, and namespace separators, and may be an empty string. Hence the $(key) syntax DGP explained.

Dossy and Helmut Giese were recently discussing variable on comp.lang.tcl. Dossy replies to a remark by Helmut:
So you have to distinguish between 'creating' a variable and
'defining' it. In your example you _create_ 'foo::bar' but don't
_define_ it. Hence [info exist] doesn't see it - as told in the book.
Ahh, yes.  Okay, so then the docs and the behavior ARE consistent, cool.  I
didn't realize that a variable could be "created" but not "exist" -- weird.
:-)

PYK 2015-02-28: info exists would have been more aptly named info set
% namespace eval foo {
    proc foo {} {
        variable myarr
        upvar somearr myarr
        parray myarr
    }
    proc foo2 {} {
        variable myarr
        namespace which -variable myarr
    }
    proc foo::foo3 {} {
        variable myarr
        info exists myarr
    }
}

% foo::foo
"myarr" isn't an array

% set somearr(x) y
y

% foo::foo
myarr(x) = y

% foo::foo2
::foo::myarr

% foo::foo3
0

[m7j4k9] 2017-08-25

If variable returned the name

Currently (8.6.4), the command
    variable name

returns nothing, but if it were to return the name, then dudes who are "into the whole brevity thing" could write:
    array set [variable foo] { this initializes {} and not foo! }

instead of:
    variable foo
    array set foo { this indeed initializes foo }

which works and intended; unlike:
    variable name { this is a dict/list and not an array }

[earnie] - 2018-06-16 13:58:27

@m7j4k9 I could see perhaps the following syntax for what you propose:
    array variable foo {initialize foo}

This would then be in keeping with the same principals as array set combined with the principals of variable.