Infix arithmetic with XOTcl

NEM 19 May 2004 - A little experiment on achieving infix arithmetic using an OO extension (in this case, XOTcl) and some cunning unknown handlers. Not particularly efficient, but it works, and is quite fun:

 # ooinfix.tcl --
 #
 #   An experiment in doing infix arithmetic using object (XOTcl) and a cunning
 #   unknown command handler to auto-convert numbers to objects (auto-boxing).
 #   Then uses an even more cunning class-level unknown handler to rewrite
 #   expressions into a format suitable for [expr].
 #
 # Neil Madden, 2004.
 # Public Domain.
 
 package require XOTcl
 
 namespace import -force ::xotcl::*
 
 # Use a single class for all numbers (rather than separate Integer and Real
 # subclasses). Just makes things easier. 
 Class Number
 Number instproc init {{val 0}} {
     my set val $val
 }
 
 Number instproc unknown {cmd args} {
     set expr [linsert $args 0 [my set val] $cmd]
     return [expr $expr]
 }
 
 # Unknown handler to do auto-conversion
 if {[string length [info commands ::_ooinfix_unknown_orig]] == 0} {
     rename ::unknown ::_ooinfix_unknown_orig
     proc ::unknown {cmd args} {
         # Does it look like a number?
         if {[string is double -strict $cmd]} {
             Number ::$cmd $cmd
             # Retry
             uplevel 1 $cmd $args
         } else {
             # Pass on to original unknown
             uplevel 1 [list ::_ooinfix_unknown_orig $cmd] $args
         }
     }
 }

Here's a little demo of it in action:

 (neilmadden) 50 % source ooinfix.tcl
 (neilmadden) 51 % 1 + 2 + 3
 6
 (neilmadden) 52 % 1 + 2 * 7
 15
 (neilmadden) 53 % set ans [12 * 15 / 22]
 8
 (neilmadden) 54 % 24.5 * 15
 367.5

It uses Tcl's built in [expr] command to do all the operator precedence and type conversions (integer/double stuff). All you need is a space before the first number and the operator - you can leave out any further spaces. Also, you can define new constants:

 (neilmadden) 55 % 24 *15/9
 40
 (neilmadden) 56 % Number pi 3.14159265
 ::pi
 (neilmadden) 57 % pi * 2
 6.2831853
 (neilmadden) 58 % set r 25
 25
 (neilmadden) 59 % set area [pi * $r ** 2]
 1963.49540625