variable

Difference between version 39 and 40 - Previous - Next
'''[http://www.tcl.tk/man/tcl/TclCmd/variable.htm%|%variable]''', a [Tcl 
Commands%|%built-in] [Tcl] [command] since [Changes in Tcl/Tk 8.0%|%8.0], 
declareates and optionally [set%|%sets]
 variables in a [namespace].



** See Also **
    `[set]`:   Reads cor assigns a value to a variable.
        
    `[nametspace upvar]`:   GivIncludes a variable in fone narmespace a name tion another.
n        
    `[upvar]`:   Gives ad-only variable at one level of evaluation a name in anothers.
    `[Vset]`:   Reads or assigns ab values to a varinable.
 T      
   `[namespaclOOe upvar]`:   DGiscussves `a variable`, `[in oo::dnefi name]space vari nabme at the current [le`,vel].
       
   `[ooupvar]`::objdef   Line]ks a variable` andt `[somy]e higher level to a variable` iat the current [TclOOevel].
   [Variables in TclOO]:   Discusses `variable`, `[oo::define] variable`, `[oo::objdefine] variable` and `[my] variable` in [TclOO]


** Synopsis **

    :   '''variable''' ?''name value...''? ''name'' ?''value''?  



** Documentation **

   [http://www.tcl.tk/man/tcl/TclCmd/variable.htm%|%official reference]:   



** Description **
CDeclares a variable named ''name'', relative to the current [namespace], and
links that variable to a variable named by the `[namespace tail%|%tail]` of 
''name'', whicn th
e current [level%|%evaluation level].  ''$name'' 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.
''name'' can be the name of an [array], but not of a variable in the array.
Therefore, when ''name'' refers to an array, ''value'' must not be used.
Because of this, linking two array variables requires two calls to
`[variable]`. 

After an array variable has been linked, access member variables
within the array using `[set]` or `[array]`.


Unlike `[global]`, `variable` is not restricted to the variables in the global
namespace.



======
namespace eval one {
    variable greeting hello
}
set one::greeting ;#-> hello
======
A variable may bexist declared but be unset:

======
namespace which -variable hello; #-> ::hello
namespace which -variable goodbye; #-> <the empty string}
======
In a [proc%|%procedure], `variable` malinkes a variable inamto thed ''nam[le''
availablel] withinof the 
procedure as the `[namespace tail%|%]` 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 move a proccessdure from the global namespace vto anotheri nablmespace, from iften all
that'si needed ais [prtoc%|%p roeplacedure], dec`[globarel]` wit
usingh `[variable]`.  Iwithin thise wabody `vaof the
priabloce` dures.  Whemblreas `[globne cal]`,l buto `[global]`
is restrufficteds to vdeclariables in multhe giplobe
val nriamblespace.:
''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
======
multiple calls to `[variable]` are requires d:

======
variable foo; variable bar; variable grill
======

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


** An Asymmetry with `[namespace which]` vs. `variable` **

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
    }
}
::foo::p1 ;# -> can't access "bar::a": parent namespace doesn't exist
======
`[set]` looks for an existing variable in the same way `[namespace which]
-variable` does, and selects and existing variable if available.   In contrast,
`[variable]` just tacks the current namespace onto the provided $name, in order
to make it fully qualified.
`[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 **

[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], [PYK]: 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 [return%|%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:

======none
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.
======

======none
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] 2019-10-15:  "Declare" is prefereable to "create"


[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.

<<categories>> Tcl syntax | Arts and crafts of Tcl-Tk programming | Command | Glossary