info level

info level indicates the current level, and can also describe the command for the current level.

See Also

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:

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:

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

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 [L1 ] 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?