[NEM] 2008-10-18: A recent question from [AM] on [comp.lang.tcl] [http://groups.google.com/group/comp.lang.tcl/browse_thread/thread/8b42068973229a2e#] asked whether it was possible to dynamically extend the methods that a [Snit] object supports after it has been created. Snit doesn't seem to have explicit support for this functionality built-in. However, it is still possible to achieve, and even quite elegantly, using the existing delegation facilities. Note that there may be other ways to do this, such as manipulating the [namespace ensemble] of a Snit object directly, but the approach here has the advantage of using only documented interfaces, and so should continue to work even if the internals of Snit change. The approach taken is to use a separate environment object that stores a dynamic map of new methods, and then delegate to this environment from the snit object you want to extend. Here we use [lambda]s for the new methods, but you could also create procedures in the instance namespace. ====== package require Tcl 8.5 package require snit 2.2 snit::type methodenv { variable methods [dict create] method define {name params body} { set params [linsert $params 0 self] set f [list $params $body] dict set methods $name $f return $name } method apply {obj name args} { ::apply [dict get $methods $name] $obj {*}$args } } ====== To enable this functionality for an object, simply install an environment as a component of your object: ====== snit::type foo { component env delegate method method to env as define delegate method * to env using "%c apply %s %m" constructor {} { install env using methodenv $self.env } } foo a a method sub {a b} { expr {$a-$b} } a method bar {} { puts "10-3 = [$self sub 10 3]" } a bar ====== There are some limitations here: only the $self variable is available in these "methods", so anything else will have to be retrieved/updated explicitly through that; also, the namespace in which the methods execute is incorrect (they execute in global ns). ------ The original example on clt was to define an extensible set of mathematical functions on an object as methods. The code for this example is also quite interesting, and demonstrates the same technique with some new twists, so is included here as well: ====== package require Tcl 8.5 ;# required package require snit 2.2 ;# may work with earlier # A function environment snit::type funcenv { constructor {} { # Make things nice for expr namespace eval $selfns\::tcl::mathfunc \ [list namespace path $selfns] } # Define a function: # env define f x y ... = expression method define {name args} { set body [list expr [lindex $args end]] set params [lrange $args 0 end-2] proc $selfns\::tcl::mathfunc::$name $params $body return $name } method apply {f args} { $selfns\::tcl::mathfunc::$f {*}$args } } snit::type numeric { component env delegate method define to env delegate method * to env using "%c apply %M" constructor {} { install env using funcenv $self.env } method interal {a b} { ... } } numeric create func func define f x = {$x*exp(-$x)} func f 1 func define g x = {$x-f($x)} func define pi = acos(-1) # ... etc ... ====== ---- !!!!!! %| [Category Example] | [Snit] |% !!!!!!