(Sorry for the long post)
Well, I've perused the archives and can't find anything on this topic. Nor can I find it in the tutorial or reference guide. So, I must conclude that I am missing something. Either this is obvious, and everyone has already figured this out. Or, there is no real need for this type of a construct and I'm thinking about this incorrectly.
Many OO languages provide a means to make some methods be polymorphic and some not. For example, C++ uses the virtual keyword to make a function polymorphic; otherwise it's not. XOTcl on the other hand appears to only support polymorphic methods. A call to a method from a given level of the hierarchy starts from the class of the calling object and works its way up (assuming next is used).
For example, a class Base provides an interface, then Sub1 and Sub2 (both subclasses of Base) provide a thin veneer on that interface. The methods have the same name. And, in some cases, they rely on Base to provide some of the functionality. But, Base provides its own functionality by composing some of its own methods into more complex methods. Now, when a method from Sub1 is called, it calls that method in Base, and Base then calls another method within Base - except that when it makes this call, it gets the version from Sub1. In some cases, this may be the correct approach. But, there are certainly cases where this is not desired.
We could try pushing some of the implementation from Base into Sub1, but Sub2 wants similar functionality. This would mean duplicating code.
Another approach might be delegation, instead of inheritance. This would work, but, all three classes (Base, Sub1, and Sub2) have instances that share a common interface. Now, to add a new method to that interface requires changing two different class hierarchies. Again, this would work, but it just doesn't feel right.
I realize that this is a fairly abstract presentation of the issue. I have attempted to come up with a simple example - for example, geometric figures, with the base class rooting the centroid at the origin to provide easy rotations. But, even here, this gets complicated. and I'm afraid that the discussion will veer off to trying to solve some particular quirk of the example. But, I have run into this issue several times, and have found it frustrating.
The only solution that I have found is to provide both an "internal" implementation and a public implementation of some methods (for example, prefix the internal method name with an underscore). Then, the implementation can decide whether it is wants to use the polymorphic method or the non-polymorphic version. But, this doesn't really solve the problem - I still have to be careful not to override the internal version (because, I don't really have a non-polymorphic method - I just have some conventions to avoid the polymorphism). This could get truly complicated with a large class hierarchy, but none of my constructs have reached the point (yet).
Actually, I can imagine a second potential solution, although I have not tried it. I think it would work, but would be very ugly. Nevertheless, I bring it up because I believe it might form the basis of what I think would be an elegant solution to this problem. I could temporarily change the class of the object to reflect where I want the method search to begin from. Then, change it back when the method returns. Artificially changing the class of an object makes me cringe - I don't really like this approach.
But, it seems to me that if XOTcl can provide a way to force the method search to begin at a particular class, this would fix the problem. Maybe something like: [self as class] <method> <args>. In fact, I think I can implement this as an Object method - simply copy the class, change it, make the call, destroy the copy, and return the result. I think this would work, and may try it. But, I still feel like I must be missing something.
Any thoughts would be appreciated.
Thanks, Kurt Stoll
You are right with your observeration, all methods in xotcl are polymorphic. This is important for orthogonality, especially, when methods invocations are interceptable as with mixin classes or filters. Here is a small example, which i think demonstrates your argument. correct me, if you have something different in mind.
============ Class Base Base instproc foo {} { puts "[self class] [self proc]" my bar a b } Base instproc bar {x y} { puts "[self class] bar $x $y" }
Class Sub -superclass Base Sub instproc bar {x y} { puts "[self class] [self proc]" }
Sub b1 b1 foo ============
the invocation of "b1 foo" calls Base->foo, the invocation of "my bar a b" calls Sub->bar, your question is, how to call Base->bar instead (like for c++ non-polymorphic methods)
As you pointed out, there are many ways to tweak the behavior. The important point is, how should/could some kind of non-polymorphic call lead to some "defensible semantics", esp. how should it behave it should behave in cases of e.g. next, or with the presence of interceptors.
The most rude apporach is to use tcl-functions instead of methods and bypass this way the xotcl dispatcher. Since every xotcl method is a tcl proc, this is doable with some little magic:
============== proc myown {proc args} {uplevel ::xotcl::classes[self class]::$proc $args} ... Base instproc foo {} { puts "[self class] [self proc]" myown bar 1 2 } ... ==============
Here, myown calls Base->bar, not Sub->bar. This is the archetype of a monoporphic call.
The downside is that the invocation of the method happens in the same xotcl frame. You might or might not be concerned about this. "logically", "bar" is invoked in Base->foo, and does not leave the callframe. Queries and calls based on the xotcl stack will reflect this, a [self proc] in bar will still return "foo", a next will call shadowed methods of "foo". By bypassing the xotcl dispatcher, filters and mixins will not be able to intercept the invocation of "Base->foo".
Another approach, as you indicated is to alter the relation between the class and the object temporarily.
============== proc as_my_instance args { set __oldclass [my info class] my class [uplevel self class] set r [uplevel my $args] my class $__oldclass set r } .... Base instproc foo {} { puts "[self class] [self proc]" as_my_instance bar 1 2 } ... ==============
while this is something which looks strange to somebody with a c++ background, this is not so far fetched, if one keeps in mind that the relation between an object and a class is just an association (like a pointer in c). The semantics are less wierd than these of the first approach: The invocation of "as_my_instance" means that everything dispatched behaves as if the object would be an instance of the current class. This will work nicely all other constructs like "next", etc. One should actually put a catch around the invocaton of the method....
Finally, the question should be adressed, whether or not the non-polymorphic call is needed. Who should call "bar" aside from "foo"? If this is something special to this class, why not model this as a proc of Base:
============== Class Base Base instproc foo {} { puts "[self class] [self proc]" [self class] bar 1 2 } Base proc bar {x y} { puts "[self ] [self proc] $x $y" }
Class Sub -superclass Base Sub proc bar {x y} { puts "[self class] [self proc]" }
Sub b1 b1 foo ============== If the behavior of "bar" needs inheritance etc, meta-classes or mixinclasses can be used. Again, there is no strange intererence with other xotcl mechanisms.
all the best -gustaf neumann