This form is an even-sized list alternating tokens and parameters. Tokens are currently either CALL, UP, or INNER, but other values may be introduced in the future. CALL indicates a procedure call, and its parameter is the corresponding info level 0. UP indicates a shift in variable frames generated by uplevel or similar, and applies to the previous CALL item. Its parameter is the level offset. INNER identifies the “inner context”, which is the innermost atomic command or bytecode instruction that raised the error, along with its arguments when available. While CALL and UP allow to follow complex call paths, INNER homes in on the offending operation in the innermost procedure call, even going to sub-expression granularity.
This information is also present in the -errorstack entry of the options dictionary returned by 3-argument catch; info errorstack is a convenient way of retrieving it for uncaught errors at top-level in an interactive tclsh.
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, procedure definitions and eval within a dynamically evaluated environment count line numbers 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 line number within the list words as well, and otherwise all line numbers 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 looking up the definition; it is implemented 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 (in such cases, using info object call as above is the simplest way of doing this by far):
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] }