I was looking idly at
http://yourbasic.org/golang/go-vs-java/, and my fingers started walking.
The most basic Tcl source for this I can think of is
proc Real c {lindex $c 0}
proc Imag c {lindex $c end}
proc Add {c d} {
lmap c $c d $d {expr {$c + $d}}
}
proc String c {
if {[lindex $c end] < 0} {
format (%g%gi) {*}$c
} else {
format (%g+%gi) {*}$c
}
}
set z {1 2}
String [Add $z $z]
But that's close to cheating. Let's at least make a class for it:
oo::class create Complex {
variable re im
constructor args {
lassign $args re im
if {$re != $re || $im != $im} {
set msg {domain error: argument not in valid range}
throw [list ARITH DOMAIN $msg] $msg
}
}
method real {} {set re}
method imag {} {set im}
method add d {
Complex new [expr {$re + [$d real]}] [expr {$im + [$d imag]}]
}
method string {} {
if {$im < 0} {
format (%g%gi) $re $im
} else {
format (%g+%gi) $re $im
}
}
}
set z [Complex new 1 2]
[$z add $z] string
And that's it. Not a big deal. Unless you're working with Java, of course.
The biggest wart AFAICS is that Tcl doesn't allow implied conversions to string: everything has a string representation, but Tcl decides what it is. In the first code, this works in our favor, as the standard string representation (a string that is a list of two numbers) is identical to the model I used for complex numbers. Without calling String, the result of Add $z $z is 2 4, which is immediately useful both for printing and for further calculations.
In the second code, the string pseudo-representation is ::oo::Obj99 (or some other number), i.e. the name of the object command. The method string needs to be called explicitly to get a printable string that shows the data content.
Note that Tcl's expr command throws an exception with the message "domain error: argument not in valid range" instead of dumping a "NaN" message. You can still figure out that it was a NaN by looking at the message or by comparing the number to itself, as I'm doing here. I could have signalled the problem with the invocation "error NaN", but chose to emulate Tcl's handling instead.