abdullam
abdullam

Reputation: 219

TCL, receive args as an argument and pass it to another procedure

I tried to do the following in TCL and got the following error "list must be an even number of elements" because $args is seen as one list when passed to B.

Is there a clever way of passing $args to B?

proc A {a args} {        
    #call B and pass it args
    B 2 $args
}

proc B {b args} {
    set options(-flag1)  0
    set options(-option) serial

    array set options $args
    #use options
}

Upvotes: 0

Views: 1898

Answers (1)

Peter Lewerin
Peter Lewerin

Reputation: 13282

Try this:

B 2 {*}$args

If we simplify the procedures a bit:

proc A args {
    puts [info level 0]
    B $args
}
proc B args {
    puts [info level 0]
}

If we call A with some values, B will receive those values packaged in a list. This list, being a single item in args, is not fit to pass to array set, since that command needs an even-sized list.

% A a b c d
A a b c d
B {a b c d}

Change the invocation of B to this:

proc A args {
    puts [info level 0]
    B {*}$args
}

Now, if we call A, each argument to A will become a distinct argument to B, and $args can now be used as an argument to array set.

% A a b c d
A a b c d
B a b c d

As nurdglaw points out, Tcl 8.4 or older does not have the {*} syntax, which means eval must be used to invoke B. One way to do it is

eval [linsert $args 0 B]

but one could also use the slightly less secure (it can lead to loss of argument structure)

eval B $args

Tcl 8.4 isn't supported any more, and there is every reason to upgrade to 8.5 or 8.6.

Documentation: eval, info, linsert, proc, puts, {*}

Upvotes: 3

Related Questions