问题
I am writing an EDA utility, relying on a TCL 8.6 compliant API. My challenge is as follows:
My utility runs on transistors' models in the database, and does some analyisis, using an EDA vendors' TCL API command. I can pass to the TCL commands a TCL procedure name/pointer, and the analysis will rely on my code, rather than the EDA vendors' code. The in-house written proc accepts as an argument a pointer to the specific transistor's instance in the EDA vendor's database.
Now, the EDA vendor allows for TCL 8.6, which means that I want to pass rather than a global proc name, or a namespace proc name, the name/pointer of the specific object's name. How do I do that? In code example:
oo:class create foo {
constructor {} {
variable numy 2
}
method fooshta { mos_pointer } {
puts "now in mosy [get name $mos_pointer ]"
}
destructor {}
}
foo create bar
analyse_tx -proc < how do I refer to bar's method fooshta?>
In a non OOP context, the code would look like:
proc fooshta { mos_pointer } {
puts "now in mosy [get name $mos_pointer ]"
}
analyse_tx -proc fooshta
As can be seen, I am looking for the answer for < how do I refer to bar's method fooshta, so that the EDA tool will invoke it for each transistors' instance? and pass the parameter?>
Thanks.
回答1:
You can't, not directly, at least not if it is going to be invoked like this:
$procname $thing_to_give_to_your_code
If instead it is invoked like this:
{*}$procname $thing_to_give_to_your_code
Then you can do it by passing in a command prefix.
analyse_tx -proc [list bar fooshta]
This is the one I'd recommend. It might also work if the invoke is done like this:
eval $procname [list $thing_to_give_to_your_code]
This sort of thing is great since it also lets you pass in things like lambda terms bound to apply
and so on. It's a very flexible system (since it actually works as a general function currying mechanism) and it's pretty simple.
However, if you're stuck with this style of invoke:
$procname $thing_to_give_to_your_code
then we have to use an indirect mechanism: an intra-interpreter alias will let us make a command (so yes, it will have a name) that delegates to the method:
# The {} are to indicate that this command is aliasing from and to the current interpreter context
interp alias {} delegate-bar-fooshta {} bar fooshta
Then we can just pass delegate-bar-fooshta
in as the command name. If you're doing this a lot, you probably ought to put the delegates inside the object's namespace context; it's probably easiest to make a method for setting things up:
oo::class create foo {
constructor {} {
variable numy 2
}
method fooshta { mos_pointer } {
puts "now in mosy [get name $mos_pointer ]"
}
destructor {}
method delegate {method args} {
# We'll also bind in any extra arguments you choose to use
interp alias {} [self namespace]::delegate-$method \
{} [self] $method {*}$args
return [namespace which delegate-$method]
}
}
foo create bar
analyse_tx -proc [bar delegate fooshta]
By doing it like this, killing off the object using the usual mechanisms will also remove the delegate commands that it owns. This is highly convenient in a complex program, as it offloads more of the housekeeping chores to Tcl itself from your script.
来源:https://stackoverflow.com/questions/41737116/pass-a-method-of-a-specific-object-as-an-input-argument-in-tcl