Hi,
I have a very philosophical question :-)
I would like to replace inheritance by delegation for some classes' instances.
e.g: Class C -parameter {delegate} # instead of Class C -superclass D C c -delegate a
where a is an object of another class, say class A.
Delegation means that: - next should call the delegate's proc/instproc - set, instvar would give access to delegate's variables (this is one of the classical delegation mechanisms/behaviour I believe?)
I have tried 3 methods, but neither work!
1) with a filter on C, which branch the methods calls to the appropriate location. the filter is defined in init: C filter CFilter
C instproc CFilter args { ::set m [[self] info calledproc] [self] instvar delegate if { ([C info instprocs $m] != "") || ([[self] info procs $m] != "") } { puts "CFilter m=$m I do it myself" next } elseif { [info exists delegate] && ($m == "set" || $m == "instvar") } { puts "CFilter m=$m I delegate it to $delegate" eval $delegate $m $args } elseif {[info exists delegate] && [[$delegate info class] info instprocs $m] != ""} { puts "CFilter m=$m I delegate it to $delegate" eval $delegate $m $args } else { puts "I dont know (m=$m), I call next" next } }
2) with a mixin on c in init: [self] mixin [$delegate info class]
3) with both
=> problem with filter only (1) : - next does not work the way I want (it does not call the delegates) - set of delegates' variables works, but instvar don't
=> problem with mixin only (2) - as the delegate's class is the mixin, it's it's methods which are always called first (but I want the delegate's methods to be called only when not existing for the class or when calling next) - I need a method in the delegate's class for every method int the class - delegate's variables are not available, of course (since I only use the class of the delegate to inherit methods)
=> mixin+filter (3) (example below) : - instvar does not work
Does someone have ideas and opinions about this? Has someone already tried? I don't remeber having found something about it in Xotcl's papers (maybe I'm wrong?).
Thanks!
"CL" == Catherine Letondal letondal@pasteur.fr writes:
CL> Hi, CL> I have a very philosophical question :-) CL> I would like to replace inheritance by delegation for some CL> classes' instances.
CL> e.g: CL> Class C -parameter {delegate} # instead of Class C -superclass D CL> C c -delegate a
CL> where a is an object of another class, say class A.
CL> Delegation means that: CL> - next should call the delegate's proc/instproc CL> - set, instvar would give access to delegate's variables CL> (this is one of the classical delegation mechanisms/behaviour I believe?)
Dear Catherine,
Your definition is not the standard definition of delegation, since delegation is not related with the ideas of "next". Informally, delegation means: don't do everything by your[self], use another object to help you. Normally, delegation is pretty much hardwired to the code.
What you are trying to do is certainly very interesting. What you are facing is however, the "inverse self problem" (Lieberman observed, that through delegation, you easily loose the [self]-reference to the callee, the method called via delegation has a different [self]; by the means of mixins or filters, we tried to find alternate ways to achieve, what delegation does, but now you seem to want delegation, and you use filters and mixins, and you wonder how to get the self of the delegate ... therefore i called the problem "inverse self problem"). Somehow i doubt that you will be happy just by using instvars in the delegate, i assume you want real delegation.
The problem is that by using "next", "mixins" etc. you do not change the active object ([self]), which is certainly quite an important assumption. I have to be convinced that this is too limited.
Below is a simple implementation, which can be made nicer by using mixins or filters, but which is quite easy to understand and could help you as a starting point. Most likely, you will want to use "handleDelegation" for all methods, therefor a filter would be appropriate, but maybe, you want to try delegation for a set of methods, therefor you could use instmixins
Suppose, an object a1 of class A wants to call a method "m". Method m has a stub for "m" that checks, whether it can delegate it (to object d1 of D) and delegates it if possible, otherwise it handles it by itself.
Note, that this works fine without to much interference with the mixins/subclasses/... for A, a1, D, d1, instvars pose no problems, etc. It is fairly trivial to extend this program to handle multiple delegation objects...
best regards -gustaf
=========================================================================
Class A -parameter delegate A instproc handleDelegation {result} { if {[[self] exists delegate]} { set context [::info level -1] # look for the called method in the delegated object if {[[[self] set delegate] procsearch [lindex $context 0]] != ""} { ::upvar $result r set r [eval [[self] set delegate] $context] return 1 } } return 0 } A instproc m {x} { if {[[self] handleDelegation r]} {return $r} else { puts "[self] [self class] [self proc] $x"; return [next] } }
Class D D instproc m {x} { puts "[self] [self class] [self proc] $x" next return [expr {$x*2 + [[self] set v]}] }
D d1 d1 set v 100 A a1 -delegate d1
puts "result=[a1 m 123]" =========================================================================