[Arjen Markus] (11 november 2008) Here is an experiment with [Snit] where I want to provide a set of methods to examine mathematical functions. It is a fairly stragihtforward exercise in wrapping procedures from [Tcllib] and [Tklib]. One particular aspect is noteworthy: in interactive use, it would be nice to invoke the function as [[f 1.0]], rather than [[f value 1.0]], as the first form is more concise and seems more natural. You need to supply an implicit method name then and this is achieved by the UnknownMethod method - the delegation mechanism in Snit works very nice. ---- ====== # function_obj.tcl -- # Mathematical functions as a Snit object # package require snit package require math::calculus package require math::optimize # function -- # Define the "function" type # ::snit::type function { typevariable top 0 delegate method * using {%s UnknownMethod %m} option -steps -default 100 constructor {arglist body args} { proc ${selfns}::F $arglist $body $self configurelist $args } method value {x} { ${selfns}::F $x } method integral {a b} { # # Romberg returns the value and an error estimate. Just return the # value of the integral. # lindex [::math::calculus::romberg [list $self value] $a $b] 0 } method table {a b} { set dx [expr {($b-$a)/double($options(-steps))}] set table {} for {set i 0} {$i <= $options(-steps)} {incr i} { set x [expr {$a + $i*$dx}] if { abs($x) < 0.5*$dx } { set x 0.0 ;# Make sure x obtains the exact value zero, # if required } set r [$self value $x] lappend table [list $x $r] } return $table } method print {a b {format {%10.4f %10.4f}}} { set table [$self table $a $b] set result "" foreach row $table { foreach {x r} $row {break} append result "[format $format $x $r]\n" } return $result } method zero {a b} { return [::math::calculus::regula_falsi $self $a $b] } method minimum {a b} { return [::math::optimize::minimum $a $b $self] } method maximum {a b} { return [::math::optimize::maximum $a $b $self] } # # Not finished yet: # TODO: scaling, determining the right widget # method plot {a b} { package require Tk package require Plotchart set table [$self table $a $b] set ymin {} set ymax {} foreach row $table { foreach {x y} $row {break} if { $ymin == {} || $ymin > $y } { set ymin $y } if { $ymax == {} || $ymax < $y } { set ymax $y } } incr top toplevel .plot$top pack [canvas .plot$top.c] set p [::Plotchart::createXYPlot .plot$top.c \ [::Plotchart::determineScale $a $b] \ [::Plotchart::determineScale $ymin $ymax]] foreach row $table { foreach {x y} $row {break} $p plot graph $x $y } } # # For interactive use, the abbreviation "f 1.0" instead of # "f value 1.0" would be very useful ... # method UnknownMethod {subcommand args} { if {[string is double -strict $subcommand]} { ${selfns}::F $subcommand } else { error "Unknown subcommand: $subcommand" } } # More to come: # - view, deriv, create-deriv, create-integral } # main -- # Testing this # function f {x} {expr {$x==0.0? 1.0 : sin($x)/$x}} puts "Value at x=0: [f 0.0]" #catch {puts [f 0.0]} msg;puts $msg; puts $errorInfo # Alternative: [f value 1.0] puts "Integral from 0 to pi: [f integral 0 [expr {acos(-1.)}]]" puts "Zero between 0 and 4: [f zero 0 4]" puts "Minimum between 0 and 10: [f minimum 0 10]" puts "Maximum between 0 and 10: [f maximum 0 10]" f plot -10 10 f configure -steps 20 puts [f print 0 8] ====== ---- MB: The core of your idea is to define the command in the constructor, which leads to the very natural definition of the function f, which in fact creates the object f as an instance of the class function. This is a clever use of SNIT, indeed. My simpler idea for that problem would have been based on a callback instead, with a client such as : ====== proc myfunc {x} {expr {$x==0.0? 1.0 : sin($x)/$x}} function f f configure -function myfunc ====== ---- !!!!!! %| [Category Snit] | [Category Mathematics] |% !!!!!!