2018-02-27

Feb 27

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.