############################################################## # define a delegate method and a default behavior for unknown ############################################################## Object instproc delegate {method obj} { my set delegate($method) $obj } Object instproc unknown {m args} { if {[my exists delegate($m)]} { eval [my set delegate($m)] $m $args } elseif {[my exists delegate(*)]} { eval [my set delegate(*)] $m $args } }This definition is sufficient for a basic implementation. We can now use the delegate method in an application. Here we use the example from the snit home page [2]. We define a class 'Tail' with a method 'wag' and Class 'Dog'. The constructor of 'Dog' creates a tail and delegates all unknown calls to the created object (of class 'Tail')
############################################################## # example from the snit homepage: A dog with a tail.... ############################################################## Class Tail -parameter {{length 5}} Tail instproc wag {} { puts "[my info parent] Wag, wag, wag." } Class Dog Dog instproc init {} { set tail [Tail new -childof [self]] my delegate * $tail } Dog instproc bark {} { puts "[self] Bark, bark, bark." }Now we can create an instance 'fido' of class 'Dog' we we call the methods 'wag' and 'bark' for the instance.
Dog fido fido wag fido barkThe output of the methods above is
::fido Wag, wag, wag. ::fido Bark, bark, bark.
GN Well, there is an updated version of delegate and unknwon based on the builtin forward, introduced by xotcl 1.3.0. This version is much faster, since it uses unknown only for the first invocation on a "delegate *" and ueses forward for later calls. This is about three times faster than the above solution.
Object instproc delegate {method obj} { if {[string first * $method]>-1} { puts stderr "storing information in [self]" my set delegate($method) $obj } else { my forward $m $obj $m } } Object instproc unknown {m args} { foreach key [my array names delegate] { if {[string match $key $m]} { set target [my set delegate(*)] my forward $m $target $m return [eval my $m $args] } } }