info level

Difference between version 21 and 22 - Previous - Next
'''`[info] [level]`''' indicates the current [level], and can also describe the command for the current level. 
** See also **
   [uplevel]:   
** See Also **

   [https://core.tcl-lang.org/tcl/tktview?name=8b9854c3d8%|%info level 0 returns incompatible result in exported command since Tcl 8.6.9], {2019 01 15}:   A description how `[info level]` behaves inconsistently in various circumstances, sometimes normalizing the name of the routine and sometimes not, and removing the ensemble name when a [namespace ensemble] is involved.  A future version of Tcl should make this more consistent.



** Synopsis **

    :   '''`info [level]`''' ?''`number`''?


** Description **

If ''number'' is specified, `[info] levels` returns a list consisting of words of the command for the level indicated by ''number''.  A number greater than `0` indicates the level identified by that number.  `0` indicates the current level, `-1` indicates one level prior to the current level, `-2` indicates the level prior to that one, and so on.

If ''number'' is not specified, `[info] level` returns a number indicating the current [level], i.e. the level from which `[info] level` was called.  `0` is top level, and each subsequent level is incremented by 1.


** Discussion **

[MGS] 2003-09-09: '''`info level 0`''' does not return values for optional arguments (if they have not been specified):

======
proc foo {bar {baz NULL}} {
    puts "info level 0 = \[[info level 0]\]"
}

# example1
foo abc def
# example2
foo abc
======

prints:

======none
info level 0 = [foo abc def]
info level 0 = [foo abc]
======

[DGP] Correct.  `info level $level` returns the substituted list of values that make up the actual command as evaluated.  

To get values for non-specified default arguments, you have to do quite a bit more work using `[info args]` and `[info default]`.

This proc will print out info for all args in the calling proc ('''note''': does not handle being called from global level).

======
proc arginfo {} {
    set proc [lindex [info level -1] 0]
    set which [uplevel [list namespace which -command $proc]]
    puts "proc \[$which\]"
    set i -1
    foreach arg [info args $which] {
        incr i
        set value [uplevel [list set $arg]]
        if { [info default $which $arg def] } {
            puts "  arg\[$i\] \[$arg\] = \[$value\] default = \[$def\]"
        } else {
            puts "  arg\[$i\] \[$arg\] = \[$value\]"
        }
    }
}

# test code
proc test {foo {"bar baz" "BAR BAZ"}} {
    arginfo
}

test abc
test abc def======
which prints the output:
======none
proc [::test]
    arg[0] [foo] = [abc]
    arg[1] [bar baz] = [BAR BAZ] default = [BAR BAZ]
proc [::test]
    arg[0] [foo] = [abc]
    arg[1] [bar baz] = [def] default = [BAR BAZ]
======
**Recursive lambda invocation**

** Recursive lambda invocation **

[AMG]: [[info level 0]] is useful for writing a lambda (anonymous procedure invoked using [apply]) that can recursively call itself despite not having a name.  See [https://wiki.tcl-lang.org/page/apply#86eba022562d2be62c0c1ac21610b579c8ab0d718f388560dd49538c1dcc88c2] for an example.

**Interaction with namespace ensemble**

[AMG]: The name of the [namespace ensemble] does not appear in the return value of [[info level 0]].

======
% namespace eval foo {
    namespace export *
    namespace ensemble create
}
% proc foo::bar {} {info level 0}
% foo bar
bar
======

I believe this happens for the same reason the namespace name is omitted from the following:

======
% namespace eval foo {}
% proc foo::bar {} {info level 0}
% namespace eval foo {bar}
bar
======

To recover the full name of the current command, use [namespace origin]:

======
% namespace eval foo {
    namespace export *
    namespace ensemble create
}
% proc foo::bar {args} {
    namespace origin [lindex [info level 0] 0]
}
% foo bar
::foo::bar
% namespace eval foo {bar}
::foo::bar
======
[PYK] 2022-03-24:  In the script above `[namespace which]` would be better than
`[namespace origin]` because the intent to fully qualify the nam of the
procedure, not to trace an imported name back to its origin.  Of course,
sometimes `[namespace origin]` is exactly what is desired.  It's just not a
synonym for `[namespace which]`.

See also: [How was I invoked?]

<<categories>> Command | Tcl syntax