I've compiled XOTcl 1.0.2 with Tcl 8.4.4 to create a xotclsh. When I execute the script below, the traced variables are unset once too few times. Also, the order of the unsetting seems odd. Am I just confused, or I have discovered a problem?
Here's the sample output:
russell> xotclsh factorial.xotcl rhs = 3 rhs = 2 rhs = 1 tracecb "rhs" "" "unset" "2" tracecb "rhs" "" "unset" "3" tracecb "f" "" "unset" "::factorial-1" tracecb "f" "" "unset" "::factorial-0" 3! = 6
File factorial.xotcl <<<<
proc tracecb { name1 name2 op } { upvar $name1 var puts "tracecb "$name1" "$name2" "$op" "$var"" }
xotcl::Class factorial; factorial proc new { args } { eval my [ my autoname factorial- ] $args }
factorial instproc compute { rhs } { puts "rhs = $rhs" if { $rhs > 1 } { set f [ factorial new ] ::trace add variable f [list unset] tracecb set lhs [ $f compute [ expr $rhs - 1 ] ] } else { set lhs 1 } set product [ expr $lhs * $rhs ] ::trace add variable rhs [ list unset ] tracecb return $product }
proc main { value } { set f [ factorial new ] puts "${value}! = [ $f compute $value ]" }
main [expr [ llength $argv ] ? [ lindex $argv 0 ] + 0 : 3 ]
Jim,
at first glance, the behavior seems ok to me. You're setting 2 traces to the local scope variable "f" which get unset in reverse order -> so the two "f" outputs should be ok.
The rhs traces "2" and "3" are for the two inner invocations. For the outer invocations, the callframe is deleted before the Trace is executed. The problem here is that Tcl does not print the error that occurs.
Consider the following plain Tcl example:
proc tracecb { name1 name2 op } { if {[catch { upvar $name1 var puts "tracecb "$name1" "$name2" "$op" "$var"" } err]} { puts $err } } proc x {a} { ::trace add variable a [list unset] ::tracecb if {$a == 0} {return} incr a -1 x $a }
x 4
This prints: tracecb "a" "" "unset" "0" tracecb "a" "" "unset" "1" tracecb "a" "" "unset" "2" tracecb "a" "" "unset" "3" can't read "var": no such variable
so you cannot rely on the "upvar" in the trace to a local scope variable.
You can try to refer to an XOTcl variable (an instance variable) with "[self] trace ..." instead.
Uwe
On Tuesday 18 November 2003 22:39, Jim Russell wrote:
I've compiled XOTcl 1.0.2 with Tcl 8.4.4 to create a xotclsh. When I execute the script below, the traced variables are unset once too few times. Also, the order of the unsetting seems odd. Am I just confused, or I have discovered a problem?
Here's the sample output:
russell> xotclsh factorial.xotcl rhs = 3 rhs = 2 rhs = 1 tracecb "rhs" "" "unset" "2" tracecb "rhs" "" "unset" "3" tracecb "f" "" "unset" "::factorial-1" tracecb "f" "" "unset" "::factorial-0" 3! = 6
File factorial.xotcl <<<<
proc tracecb { name1 name2 op } { upvar $name1 var puts "tracecb "$name1" "$name2" "$op" "$var"" }
xotcl::Class factorial; factorial proc new { args } { eval my [ my autoname factorial- ] $args }
factorial instproc compute { rhs } { puts "rhs = $rhs" if { $rhs > 1 } { set f [ factorial new ]
::trace add variable f [list unset] tracecb set lhs [ $f compute [ expr $rhs - 1 ] ] } else { set lhs 1 } set product [ expr $lhs * $rhs ] ::trace add variable rhs [ list unset ] tracecb return $product
}
proc main { value } { set f [ factorial new ] puts "${value}! = [ $f compute $value ]" }
main [expr [ llength $argv ] ? [ lindex $argv 0 ] + 0 : 3 ]
Xotcl mailing list - Xotcl@alice.wu-wien.ac.at http://alice.wu-wien.ac.at/mailman/listinfo/xotcl
Uwe:
Thank you so much for the very lucid explanation. I was hoping that I could use the trace mechanism to implement a garbage collection scheme. I was storing the XOTcl object name in an ordinary Tcl variable upon which I placed the unset trace. When the variable goes out of scope, the unset callback is called, and I had hoped to dereference the variable to call the XOTcl object's destroy method. However, this doesn't appear to be a good approach. Do you have any suggestions?
Jim
Uwe Zdun wrote:
Jim,
at first glance, the behavior seems ok to me. You're setting 2 traces to the local scope variable "f" which get unset in reverse order -> so the two "f" outputs should be ok.
The rhs traces "2" and "3" are for the two inner invocations. For the outer invocations, the callframe is deleted before the Trace is executed. The problem here is that Tcl does not print the error that occurs.
Consider the following plain Tcl example:
proc tracecb { name1 name2 op } { if {[catch { upvar $name1 var puts "tracecb "$name1" "$name2" "$op" "$var"" } err]} { puts $err } } proc x {a} { ::trace add variable a [list unset] ::tracecb if {$a == 0} {return} incr a -1 x $a }
x 4
This prints: tracecb "a" "" "unset" "0" tracecb "a" "" "unset" "1" tracecb "a" "" "unset" "2" tracecb "a" "" "unset" "3" can't read "var": no such variable
so you cannot rely on the "upvar" in the trace to a local scope variable.
You can try to refer to an XOTcl variable (an instance variable) with "[self] trace ..." instead.
Uwe
Hi!
the -volatile option of new does something like this for local objects in the current scope (it uses an "unset" trace set in C). Example:
package require XOTcl namespace import ::xotcl::*
Class A A instproc destroy args { puts "I'm destroyed: [self]" next } A proc x {} { A new -volatile } A x
Does this help?
Uwe
On Wednesday 19 November 2003 16:53, Jim Russell wrote:
Uwe:
Thank you so much for the very lucid explanation. I was hoping that I could use the trace mechanism to implement a garbage collection scheme. I was storing the XOTcl object name in an ordinary Tcl variable upon which I placed the unset trace. When the variable goes out of scope, the unset callback is called, and I had hoped to dereference the variable to call the XOTcl object's destroy method. However, this doesn't appear to be a good approach. Do you have any suggestions?
Jim
Uwe Zdun wrote:
Jim,
at first glance, the behavior seems ok to me. You're setting 2 traces to the local scope variable "f" which get unset in reverse order -> so the two "f" outputs should be ok.
The rhs traces "2" and "3" are for the two inner invocations. For the outer invocations, the callframe is deleted before the Trace is executed. The problem here is that Tcl does not print the error that occurs.
Consider the following plain Tcl example:
proc tracecb { name1 name2 op } { if {[catch { upvar $name1 var puts "tracecb "$name1" "$name2" "$op" "$var"" } err]} { puts $err } } proc x {a} {
::trace add variable a [list unset] ::tracecb
if {$a == 0} {return} incr a -1 x $a }
x 4
This prints: tracecb "a" "" "unset" "0" tracecb "a" "" "unset" "1" tracecb "a" "" "unset" "2" tracecb "a" "" "unset" "3" can't read "var": no such variable
so you cannot rely on the "upvar" in the trace to a local scope variable.
You can try to refer to an XOTcl variable (an instance variable) with "[self] trace ..." instead.
Uwe
Xotcl mailing list - Xotcl@alice.wu-wien.ac.at http://alice.wu-wien.ac.at/mailman/listinfo/xotcl
XOTcl is so cool! I like it so much better than incrTcl. This is exactly what I was looking for. Thank you so much for the help.
Jim
Uwe Zdun wrote:
Hi!
the -volatile option of new does something like this for local objects in the current scope (it uses an "unset" trace set in C). Example:
package require XOTcl namespace import ::xotcl::*
Class A A instproc destroy args { puts "I'm destroyed: [self]" next } A proc x {} { A new -volatile } A x
Does this help?
Uwe
On Wednesday 19 November 2003 16:53, Jim Russell wrote:
Uwe:
Thank you so much for the very lucid explanation. I was hoping that I could use the trace mechanism to implement a garbage collection scheme. I was storing the XOTcl object name in an ordinary Tcl variable upon which I placed the unset trace. When the variable goes out of scope, the unset callback is called, and I had hoped to dereference the variable to call the XOTcl object's destroy method. However, this doesn't appear to be a good approach. Do you have any suggestions?
Jim, i have simplified your example by deleting the trace calls and your replacemented of "new" and added simply "-volatile". When an object is created with "new -volatile" it will be destroyed automatically, when the current tcl-proc/object-proc/instproc is left.
So, after main is processed, all instances of factorial are deleted.
Was this, what you were looking for?
######################################### xotcl::Class factorial factorial instproc compute { rhs } { puts "rhs = $rhs" if { $rhs > 1 } { set f [ factorial new -volatile ] set lhs [ $f compute [ expr $rhs - 1 ] ] } else { set lhs 1 } set product [ expr $lhs * $rhs ] return $product }
proc main { value } { set f [ factorial new -volatile] puts "${value}! = [ $f compute $value ]" }
main [expr [ llength $argv ] ? [ lindex $argv 0 ] + 0 : 3 ] ################################################
Another simple approach for some kind of "garbarge collection" in xotcl is to put your temporary objects into a container and delete that when appropriate.
best regards -gustaf