Version 5 of Deferred evaluation

Updated 2002-05-15 08:10:33

Richard Suchenwirth 2002-04-28 - Here is an attempt to model deferred evaluation with traces: three lines of code in willset (the will indicating future tense, of course ;-) exercise all subcommands of the trace command. First a previous trace is checked and possibly deleted, then the new one registered. The idea is that a variable is "bound to" a "body" which is executed when the variable value is retrieved, so references to other variables are re-evaluated, and changes to them reflected accordingly. Example:

 set a {1 2}
 set b {3 4}
 willset c {list $a $b} => {1 2} {3 4}
 set b {30 4}
 set c => {1 2} {30 4}

 proc willset {varName body} {
        set trace [uplevel 1 trace vinfo $varName] ;# have previous?
        if {$trace != ""} {uplevel 1 eval trace vdelete $varName $trace}
        uplevel 1 [list trace var $varName r "set $varName \[$body\];#"]
        uplevel 1 [list set $varName]
 }

As shown above, deferred assignment with willset easily passes the test given by davidw in linked lists. His added requirement for garbage collection does not seem to be an issue - the trace to an willset variable is automatically deleted when the variable ceases to exist.

As shown by Arjen Markus before, linked lists and whatever references may be good for can be implemented in Tcl. It's just that Tcl references are not "physical" pointers, but (as usual) strings: variable names, which are mapped to physical pointers in an internal hash table. The problem of "dangling references" (stored references to objects that do no more exist) is likewise there, but if it occurs, it is rather clearly reported and does not lead to a segmentation fault:

 % set a [list 1 2]
 % set b [list 3 4]
 % willset c {list $a $b}
 {1 2} {3 4}
 % set b [list 30 4]
 30 4
 % set c
 {1 2} {30 4}
 % unset a
 % set c
 can't read "c": can't read "a": no such variable

Introspection was not explicitly coded: find out what body is tied to a variable with

 trace vinfo c

Mixing eager assignment (with set) and lazy assignment (with willset) currently has the troublesome property that the set returns the new value, but later accesses still fire the trace:

 % set c hello => hello
 % set c   0> {1 2} {30 4}

Obviously, this isn't a finished solution yet... the following write trace didn't work out:

        #set writetrace "trace vdelete $varName \[trace vinfo $varName\];#"
        #uplevel 1 trace var $varName w $writetrace

Maybe raising an error is enough for the write trace. Come to think, willset suddenly resembles dynavar from Braintwisters:

 willset now {clock format [clock seconds] -format %H:%M:%S}
 0 % set now
 19:37:12
 0 % set now
 19:37:14

Various other probes into deferred evaluation:

  • Streams - generator-like procs with state
  • forall - custom control structurs for logical quantifiers

Category Concept - Arts and crafts of Tcl-Tk programming