Updated 2013-04-02 20:31:51 by pooryorick

Summary  edit

"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).