Reputation: 279
please find below a snippet of code that passes an array, manipulates the array, but i cannot return the new version of array.
here is the snippet :
proc get_mroute_active { &multicast } {
upvar ${&multicast} MULTICAST ;
set group -1 ;
set src -1 ;
set mcast_group_source_id -1 ;
set MULTICAST($mcast_group_source_id,id) $mcast_group_source_id ;
set MULTICAST($mcast_group_source_id,mcast_group) $group ;
set MULTICAST($mcast_group_source_id,mcast_source) $src ;
puts [array size MULTICAST] ;
parray MULTICAST ;
}
array set multicast { } ;
get_mroute_active [array get multicast] ;
puts [array size multicast] ;
parray multicast ;
And the output of the code is :
3
MULTICAST(-1,id) = -1
MULTICAST(-1,mcast_group) = -1
MULTICAST(-1,mcast_source) = -1
0
Could you please help show me how the "MULTICAST" variable can be assigned to "multicast" ?
Upvotes: 3
Views: 5183
Reputation: 55443
The short answer is: you can't return an array from a procedure as arrays are not values — they are peculiar named collections of named values.
There are several ways to deal with this:
The usual approach is to pass arrays by names and make the called procedure modify the array in place. For instance, the code
proc foo {arrayName} {
upvar 1 $arrayName ary
incr ary(one)
}
set x(one) 1
foo x
puts $x(one)
will print "2" as the procedure foo
modified a specific value in the specified array in the caller's scope.
Notice how the caller passed the name of an array, "x", instead of "its value" (as you cannot extract a value from an array; but see below) and then the called procedure bound a local variable to that array by its name using the upvar
command.
The other approach is to employ array get
and array set
commands to extract keys and values from arrays and populate arrays with keys and values, respectively. For instance:
set x(one) 1
set x(two) 2
array set another [array get x]
parray another
would print
another(one) = 1
another(two) = 2
The array get
command, given an array, returns a flat list with its keys and their respective values interleaved. This way you can return the contents of an array from a procedure and then make the caller do whatever it wishes with these contents, for instance, use the array set
command to populate another array in its scope (possibly the same which has been passed to that procedure in the first place).
Note that array set
has merge semantics: it does not empty the target array before inserting/replacing its values using the source list.
The third (and may be the best) approach is to use dictionaries which are key/value maps as arrays do but are themselves values, so they can be passed around freely as other values. This requires Tcl 8.5 or later (in Tcl 8.4, you can use a backport of this code in the form of a package. With dict
s you get it like this:
proc foo d {
dict set d one 2
return $d
}
set x [dict create]
dict set x one 1
set y [foo $x]
puts $y
which would print "one 2" as the procedure modified the original dictionary then returned it and then the caller assigned it to another variable.
Upvotes: 5