Reputation: 4938
This is Tcl 8.4.
I'm trying to make a procedure that can do something common on any other procedure specified by the user.
For example:
proc process_menu_item {command args {count 1}} {
set inf [expr {$count == -1 ? 1 : 0}]
set end_str [expr {$count == -1 ? "inf" : $count}]
set loop_cnt 0
while {$inf || $count > 0} {
incr loop_cnt
puts [format "------- %s -------" [bold "LOOP $loop_cnt of $end_str"]]
$command $args
}
return
}
This procedure, I hoped, will just execute the specified $command $count times. The problem I run into is with passing the arguments.
Let's assume I want to call a procedure like this:
proc example {{par_a {-1}} {par_b {-1}} {par_c 1}} {
puts "All params: $par_a $par_b $par_c"
}
How should I call process_menu_item
? Is it even possible? I tried a string, a list, but eventually par_a
gets a big list of all the arguments.
Thank you.
Upvotes: 2
Views: 15234
Reputation: 246807
I'm not able to give a more comprehensive answer right now, but interp alias
might get you where you want to go. There's an example at rosettacode.org. If that doesn't fit, perhaps explore command traces -- those fire for every command and you can make choices based on the command name.
Upvotes: 0
Reputation: 137567
(First off, the args
parameter to a procedure is only magical when it is last. Put anything after it and it becomes just an ordinary variable. Just so you know. Of course, that might even be what you need here!)
To call out of process_menu_item
, you'd want to change:
$command $args
to this (Tcl 8.4 or earlier):
eval $command $args
Well, if you are paranoid you actually write this:
eval [list $command] [lrange $args 0 end]
Or you use Tcl 8.5 (or later):
$command {*}$args
Then, you'd probably build the call to process_menu_item
like this:
process_menu_item frobnicate [list foo bar]
There are a few other ways to do it rather than using list
(many Tcl commands can produce lists) or you could use a literal:
process_menu_item frobnicate {foo bar}
What isn't recommended is putting anything in that literal refers to variables inside process_menu_item
(which would only work with the shortest eval
-based form). It lets you do awesome stuff, but it's also incredibly fragile. If you want to pass in the loop variable, that's quite possible but it requires techniques that are a little more advanced (and you should ask another question).
Upvotes: 4
Reputation: 45057
You can always construct a wrapper function:
proc wrapper {arg_list} {
example [lindex $arg_list 0] [lindex $arg_list 1] [lindex $arg_list 2]
}
TCL 8.5 has the {*}
operator which was designed for this sort of thing:
% proc test {a b c} {
puts a
puts b
puts c
}
%
% set inp [list "A" "B" "C"]
A B C
% test $inp
wrong # args: should be "test a b c"
% test {*}$inp
a
b
c
Upvotes: 2