References to proc-local vars

Fredderic suggested in c.l.t [L1 ] that absolute references to proc-local variables might be useful. It is of course necessary for such references to cease to be valid when the proc returns.

I propose here a small implementation of such things (NOT TESTED!):

  • set ref [::REF:: myVar] will create a global variable named $ref that is linked to the local variable myVar
  • a variable REFERENCES is created in caller's scope, with unset traces that cleanup all references created in its scope. These will be triggered by the caller returning.

This is quite simplistic, a proper implementation needs some more care. For instance, references to namespace variables do not need this machinery and a FQ name is what should be returned.

namespace eval REF {
    variable count 0
    proc {} varName {
        # Create a namespace variable to store the local's data, intitialize it
        # with localvar's value and create a simple alias for it in the context
        # of the current proc

        upvar 1 $varName localVar

        if {[array exists localVar]} {
            # this does not (yet?) work for arrays: need more work in the
            # transfer of values and traces

            return -code error "REF: references to array \"$varName\" not yet implemented"
        }

        variable count
        set refName ::REF::ref_[incr count]
        upvar 0 $refName ref
        set ref $localVar

        # Transfer any traces from localVar to ref

        foreach t [trace info variable localVar] {
            trace add variable ref {*}$t
            trace remove variable localVar $t
        }

        # Now unset localVar and link it in the caller to the newly created
        # reference

        unset localVar
        uplevel 1 [list upvar #0 $refName $varName]


        # Insure that the reference is cleaned up when the caller exits

        upvar 1 REFERENCES allRefs
        trace add variable allRefs unset "unset -nocomplain ::REF::$refName ;#"

        return $refName
    }