Other types may be also registered as well. See Tcl_RegisterCommandTypeName.
The description is a dictionary of tokens and parameters. Tokens are currently either CALL, UP, or INNER, but other values may be introduced in the future. CALL indicates a command 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 provide a trail of the call path, INNER provides details of the offending operation in the innermost procedure call, even 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 interpreter.
If depth is greater than 0 it is the frame at that depth. Otherwise it is the number of frames up from the current frame.
As with info level and error traces, for nested commands like “foo [bar [x]]”, only “x” is seen by info frame invoked within “x”.
The dictionary may contain the following keys:
When a command can be traced to its literal definition in some script, e.g. procedures nested in statically defined procedures, and literal eval scripts in files or statically defined procedures, its type is source and its location is the absolute line number in the script. Otherwise, its type is proc and its location is its line number within the body of the procedure.
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, and the call chains that this command files do not actually contain private methods.
If class does not provide a definition namespace of the given kind, this command returns the empty string. In those circumstances, the oo::define and oo::objdefine commands look up which definition namespace to use using the class inheritance hierarchy.
Note that there is no inspection of whether the method implementations actually use next to transfer control along the call chain, and the call chains that this command files do not actually contain private methods.
Implementation note: the creation identifier is used to generate unique identifiers associated with the object, especially for private variables.
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] }