If number is positive (> 0) then it selects a particular stack level (1 refers to the outer-most active command, 2 to the command it called, and so on, up to the current frame level which refers to info frame itself); otherwise it gives a level relative to the current command (0 refers to the current command, i.e., info frame itself, -1 to its caller, and so on).
This is similar to how info level works, except that this subcommand reports all frames, like sourced scripts, evals, uplevels, etc.
Note that for nested commands, like “foo [bar [x]]”, only “x” will be seen by an info frame invoked within “x”. This is the same as for info level and error stack traces.
The result dictionary may contain the keys listed below, with the specified meanings for their values:
A thing of note is that for procedures statically defined in files the locations of commands in their bodies will be reported with type source and absolute line numbers, and not as type proc. The same is true for procedures nested in statically defined procedures, and literal eval scripts in files or statically defined procedures.
In contrast, a procedure definition or eval within a dynamically evaluated environment count linenumbers relative to the start of their script, even if they would be able to count relative to the start of the outer dynamic script. That type of number usually makes more sense.
A different way of describing this behaviour is that file based locations are tracked as deeply as possible, and where this is not possible the lines are counted based on the smallest possible eval or procedure body, as that scope is usually easier to find than any dynamic outer scope.
The syntactic form {*} is handled like eval. I.e. if it is given a literal list argument the system tracks the linenumber within the list words as well, and otherwise all linenumbers are counted relative to the start of each word (smallest scope)
Note that there is no inspection of whether the method implementations actually use next to transfer control along the call chain.
Note that there is no inspection of whether the method implementations actually use next to transfer control along the call chain.
proc printProc {procName} { set result [list proc $procName] set formals {} foreach var [info args $procName] { if {[info default $procName $var def]} { lappend formals [list $var $def] } else { # Still need the list-quoting because variable # names may properly contain spaces. lappend formals [list $var] } } puts [lappend result $formals [info body $procName]] }
oo::class create c c create o puts [info object class o] → prints "::c" puts [info object class c] → prints "::oo::class"
The introspection capabilities can be used to discover what class implements a method and get how it is defined. This procedure illustrates how:
proc getDef {obj method} { foreach inf [info object call $obj $method] { lassign $inf calltype name locus methodtype # Assume no forwards or filters, and hence no $calltype # or $methodtype checks... if {$locus eq "object"} { return [info object definition $obj $name] } else { return [info class definition $locus $name] } } error "no definition for $method" }
This is an alternate way of implementing the definition lookup is by manually scanning the list of methods up the inheritance tree. This code assumes that only single inheritance is in use, and that there is no complex use of mixed-in classes:
proc getDef {obj method} { if {$method in [info object methods $obj]} { # Assume no forwards return [info object definition $obj $method] } set cls [info object class $obj] while {$method ni [info class methods $cls]} { # Assume the simple case set cls [lindex [info class superclass $cls] 0] if {$cls eq {}} { error "no definition for $method" } } # Assume no forwards return [info class definition $cls $method] }