Richard Suchenwirth 2005-03-25 - TOOT is "transparent OO for Tcl" - a "pure-value" approach, where a value (a listable string) like
{Foo | bar grill}
is interpreted to be of class Foo (so Foo's methods can be applied to it), with the "instance variable" values bar and ''grill'. (In fact, they aren't "variable" - values are immutable).
The "|" as second element just identifies this as a TOOT value. "Transparent" means that a TOOT has nothing to hide - its state is fully visible in the string representation. For a "constructor", list is sufficient:
set c [list Complex | $real $imag]
but a few keystrokes add "constructor sugar", so you might as well call
set c [Complex | $real $imag]
No garbage collection is necessary: like all Tcl values, TOOT values just go away when nobody wants them any more (e.g. on return when associated with a local variable).
Methods are called as usual, with the method name (which can also look like "+") after the object, and then possibly more arguments. The example with the multiplication method named, evidently, "*" shows that the appearance of infix arithmetics comes as a by-product:
set i {Complex | 0 1} ;#-- imaginary unit i $i * $i ==> {Complex | -1 0} ;#-- such that i*i == -1
Reinventing Complex math made simple, here's my experiments. Binary operators take one argument, which can be another Complex, or a real number x, which then gets "upgraded" to [Complex | $x 0]. A single proc contains all methods for the Complex "class":
proc Complex {| r i {method ""} args} { if {[llength $args]==1} { set operand [lindex $args 0] if [string is double -strict $operand] { set r2 $operand; set i2 0 } else {foreach {Complex | r2 i2} $operand break} } switch -- $method { "" {list Complex | $r $i ;#--constructor sugar} real {set r} imag {set i} abs {expr {hypot($i,$r)}} arg {expr {atan2($i,$r)}} format {expr {$i ? "$r+i*$i" : $r}} == {expr {$r==$r2 && $i==$i2}} != {expr {!($r==$r2 && $i==$i2)}} + {Complex | [+ $r $r2] [+ $i $i2]} - {Complex | [- $r $r2] [- $i $i2]} * {Complex | [expr {$r*$r2 - $i*$i2}] \ [expr {$r*$i2 + $r2*$i}] } / {set div [expr {$r2*$r2 + $i2*$i2}] Complex | [expr {($r*$r2 + $i*$i2) / $div}] \ [expr {($r2*$i - $r*$i2) / $div}] } default {error "unknown method $method"} } } #-- For convenience, [expr] operators are exported as commands: foreach op {+ - * /} {proc $op {a b} "expr {\$a $op \$b}"}
To make this flavor of TOOT work, we let unknown know it shall auto-expand the first word if its second element is "|" :
proc know what {proc unknown args $what\n[info body unknown]} know { if {[lindex $args 0 1] eq "|"} { return [uplevel 1 [lindex $args 0] [lrange $args 1 end]] } } #-- This little tester reports the unexpected proc ? {cmd expected} { catch {uplevel 1 $cmd} res if {$res ne $expected} {puts "$cmd -> $res, expected $expected"} } #-- The test suite passes silently when all goes well: set i {Complex | 0 1} ;# flat value set b [Complex | 3 4] ;# constructor sugar ? {$b format} {3+i*4} ? {$b abs} 5.0 ? {$b real} 3 ? {$b imag} 4 ? {$i == $i} 1 ? {$i == $b} 0 ? {$i != $b} 1 ? {$i + $b} {Complex | 3 5} ? {$b - $i} {Complex | 3 3} ? {$b + 1} {Complex | 4 4} ? {$i * $i} {Complex | -1 0} ;# i**2 == -1? ? {[$i * $i] format} -1 set r [$b abs] set phi [$b arg] ? {[[Complex | [expr cos($phi)] [expr sin($phi)]] * $r] == $b} 1 ? {$b / 0} "divide by zero" ? {$b / {Complex | 0 0}} "divide by zero" ? {$a foo} "unknown method foo"
See also Straightforward implementation of complex numbers which is included in recent Tcllib