Dear all,
first, a happy new year to everybody!
Eckhard Lehmann schrieb:
Especially I look for a way to execute a proc before *every* statement inside an instproc. [trace] can do this via the "enterstep" and "leavestep" operators to [trace add execution]. Is this possible with filters and filterguards?
Here is a small example for tracing the calls within a method ("doit"), which is somewhat similar to enterstep. Given is the following sample script:
========================== Class A A instproc foo {} { my set f 2 } A instproc doit {args} { my set a 3 } Class B -superclass A B instproc doit {args} { my set x 1 my foo next my set y 4 } B b1 ==========================
for this script, we can define a filter, which uses call stack introspection (self callingproc) to check, whether the current execution is within the method "doit".
========================== Class F F instproc traceFilter args { if {[self callingproc] eq "doit"} { puts "Call: [self] [self calledproc] $args" set r [next] puts "Exit: [self] [self calledproc] $args => $r" return $r } else { next } } ==========================
we add the method via mixin and register the filter to to all instances of Class B and call the method,
========================== B instmixin F B instfilter {{traceFilter}} b1 doit ==========================
The output is as follows:
Call: ::b1 set x 1 Exit: ::b1 set x 1 => 1 Call: ::b1 foo Exit: ::b1 foo => 2 Call: ::b1 set a 3 Exit: ::b1 set a 3 => 3 Call: ::b1 set y 4 Exit: ::b1 set y 4 => 4
Note, that it just traces on the level of doit. This is not the same, what tcl command traces provide (which is more of a debugging tool), but filters are in some respects more general: one can use traces as glueing code between invocations, restrict the traces to certain objects or instances of classes, one can stack multiple filters, or can provide different guard conditions for different subclasses, etc.
tcl command traces just know about tcl-commands and nothing about OO concepts, they allow to register other tcl commands to be executed at certain checkpoints (e.g. one command before the invocation, another command after invocation), but it does not provide e.g. means to pass information between the before and after calls. that is much easier with the "next" metapher in xotcl, which is uniform to all other supported concepts.
i have not felt so far the need for tcl command traces, but i understand, that for people used to it there is a change in the method-set and thinking involved to move from command traces towards filters/mixins.
Allthough all xotcl methods are commands, with the current framework, the tcl command traces are not called autmatically, since the basic invocation mechanisms (with inheritance, filters, mixins) are handled by xotcl. Without looking into the details, i think it should be possible with moderate effort to incorporate tcl command traces in xotcl. But one has to convince the developers, that adding yet another interception mechanism to xotcl adds more benefits than causing confusion.
-gustaf neumann
PS: The example above can be implemented nicer of filterGuards, but unfortuantely, there is a bug in the current release (most likely since ever) within the evaluation of callstack introspection commands from within a guard. This bug will be removed in the forthcoming release, where one can write:
F instproc traceFilter args { puts "Call: [self] [self calledproc] $args" set r [next] puts "Exit: [self] [self calledproc] $args => $r" return $r }
B instfilter {{traceFilter -guard { [self callingproc] eq "doit" }}}