"pass-by-
reference", aka "call-by-reference" is a term used in languages such as
C and
C++. This page investigates what that phrase might mean in terms of
Tcl Resources edit
- Lvalue - Rvalue distinctions
See Also edit
- Implicit upvar
- a later alternative to xproc
- use_refs
- references in Tcl (a simple approach)
Description edit
Those new to Tcl, especially coming from languages like C, wonder about the performance implications of passing "by value" vs "by reference". For example, would be more efficient for
[lindex] to take as an argument the name of the list rather than the list itself?
Historically (prior to Tcl version 8), there was some merit to this line of thinking, but in newer versions,
Tcl is generally doesn't make copies of values until necessary, so, e.g, passing a large list as an argument to a procedure isn't by itself a problem.
The Tcl equivalent of "by reference" is to pass in the name of a variable, and let the procedure look it up using
[upvar]. This isn't usually done for performance, but for the purpose of modifying the value in-place. The
[upvar] variant will probably take slightly longer because of the call to
[upvar], but passing the argument "by value" won't in and of itself affect performance.
A Pass at Pass by Reference edit
KPV: After having read a criticism of tcl that it doesn't have true pass by
reference --you have to fake it with using
upvar -- I thought I'd write a tcl-only clone of
proc called
xproc that will automatically give you pass by reference ala
C++ syntax. Specifically, you say
proc myproc {arg1 &arg2 arg3 &arg4} {body} and
arg2 and
arg4 will automatically be pass by reference.
proc xproc {pname arglist body} {
set preamble ""
foreach arg $arglist {
set arg [lindex $arg 0]
if {[string match "&*" $arg]} {
set barearg [string range $arg 1 end]
append preamble "upvar 1 \[set [list $arg]\] [list $barearg]\n"
}
}
proc $pname $arglist "$preamble#original body follows:\n$body"
}
AvL: I simplified the xproc-implementation, and made it more robust against nasty variable names
Here's a sample usage:
xproc myproc {&arr} {
foreach n [array names arr] {
puts "arr($n) => $arr($n)"
}
}
array set myarray {1 one 2 two 3 three}
myproc myarray
RS: Nice! I'd like to speak in defense of
upvar, which is no black magic, but just a scoping mechanism. Like everything, references in Tcl are strings, implemented as variable names, which are valid in their scope. Now as proc variables normally have local scope (which is a good thing!), you have to dereference variables from other (only upper) scopes if required, and that is precisely what
upvar does. And: even seeming innocent statements like
set i 0
already contain a reference - to the variable "i". In general, every time you mention a variable name without prefixing it with $, you're working with a reference. (See
Dangers of creative writing for a list of commands that use references, and possibly create new variables).