Version 18 of Pass by reference

Updated 2019-03-05 20:00:35 by kpv

Summary

"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

Lvalue - Rvalue distinctions

See Also

Description

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

Keith Vetter 2002-09-19 : 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).