View · Search · Index
No registered users in community xowiki
in last 10 minutes

Re: [Xotcl] Non-polymorphic methods (long post)

From: Gustaf Neumann <neumann_at_wu-wien.ac.at>
Date: Sun, 26 Feb 2006 19:52:11 +0100

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