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