Multiple inheritance with metaclasses not setup
correctly: this is
a bug, which I have tried to explain/report to
Bo:blingen for years, but was not really
successful. This is a new attempt to describe/demo the
problem. The enclosed program
"testmc.rex" contains four metaclasses:
one metaclass ("Counter") which counts the number
of times an instance of a class is
created by intercepting the message "new",
counting its invocation and forwarding to
the superclass to do the actual instantiation,
one metaclass ("Singleton") which implements the
singleton pattern, ie. no matter how
many times an instance is requested, only one will
be created and returned,
one metaclass ("Counter_Singleton"): subclasses
"Counter", inherits "Singleton" used
in object class "testCS",
one metaclass ("Singleton_Counter"): subclasses
"Singleton", inherits "Counter" used
in object class "testSC".
It seems, that the inherited class(es) are not looked
up on method resolution (e.g.
forwarding NEW and rgfTest to super would print out
the name of the metaclass and the
method running: NEW should appear twice for each
object, once in "Counter" and once in
"Singleton", sequence depending on which metaclass is
used to build class object from.
The output from running this program is attached as well.
Anonymous
Contains program and output
Logged In: YES
user_id=1125291
I'm afraid you are still unsuccessful in explaining what the
problem is. This program spits out a lot of information,
but I don't see any explanation of what you are expecting to
happen (and why), and why the current behavior is incorrect.
Please elaborate.
Logged In: YES
user_id=662126
O.K., the problem may be even more subtle, therefore I
created a shorter
example, where there are two classes "ABC" and "XYZ", both
having a method
"INIT" and a method "HELLO". The class "XYZ" inherits via
multiple
inheritance from "ABC" and makes sure that in its methods
"INIT" and "HELLO"
the superclass (= "ABC") methods are invoked via "FORWARD
CLASS (super)".
In the program "test1.rex" below, the classes "ABC" and
"XYZ" specialize the
Object Rexx root class "OBJECT". The output shows, that
indeed the methods
"INIT" and "HELLO" are carried out by the class "XYZ" and
via inheritance in
class "ABC" as well.
In the program "test2.rex" below, the classes "ABC" and
"XYZ" specialize the
Object Rexx root class "CLASS". The output shows, that
indeed the methods
"INIT" and "HELLO" are carried out by the class "XYZ" and
via inheritance in
class "ABC" as well.
The program "test3.rex" extends "test2.rex" by adding a
new class "TEST",
which specializes the root class "OBJECT", but determines
via METACLASS that
"XYZ" should be used to create its class object. It is in
this combination that
all of a sudden the multiple inheritance mechanism does not
work anymore, as can
be seen by the output as well. This is the reason for
inferring that employing
multiple inheritance among metclasses is erroneous.
What follows are the three small test programs, and after
that the output of
each of these three programs generate, including the error
message for
"test3.rex".
------------------ begin: test1.rex ----------------
say copies("=", 50)
say "Start of main program..."
say
x=.xyz~new
x~hello -- send hello
say copies("-", 50)
::routine pp
return "[" || arg(1)~string || "]"
::class ABC mixinclass Object
::method init
say pp(self) "("self~"=="~c2x"): class ABC ,method INIT."
::method hello
say pp(self) "("self~"=="~c2x"): class ABC ,method HELLO."
::class XYZ mixinclass Object INHERIT ABC
::method init
say pp(self) "("self~"=="~c2x"): class XYZ ,method INIT."
forward class (super)
::method hello
say pp(self) "("self~"=="~c2x"): class XYZ ,method HELLO."
forward class (super)
------------------ end: test1.rex ----------------
------------------ begin: test2rex ----------------
say copies("=", 50)
say "Start of main program..."
say
x=.xyz~new("MnO")
x~hello -- send hello
say copies("-", 50)
::routine pp
return "[" || arg(1)~string || "]"
::class ABC mixinclass Class
::method init
say pp(self) "("self~"=="~c2x"): class ABC ,method INIT."
::method hello
say pp(self) "("self~"=="~c2x"): class ABC ,method HELLO."
::class XYZ mixinclass Class INHERIT ABC
::method init
say pp(self) "("self~"=="~c2x"): class XYZ ,method INIT."
forward class (super)
::method hello
say pp(self) "("self~"=="~c2x"): class XYZ ,method HELLO."
forward class (super)
------------------ end: test2.rex ----------------
------------------ begin: test3.rex ----------------
say copies("=", 50)
say "Start of main program..."
say
x=.test~new
co=x~class -- get the class object
say "class-object:" pp(co)", the class object's metaclass:"
pp(co~metaclass)
say
say "invoking the class method 'HELLO':"
co~hello -- send hello does NOT work anymore
(".test~hello" wouldn't work either)
say copies("-", 50)
::routine pp
return "[" || arg(1)~string || "]"
::class test metaclass xyz
::class ABC mixinclass Class
::method init
say pp(self) "("self~"=="~c2x"): class ABC ,method INIT."
::method hello
say pp(self) "("self~"=="~c2x"): class ABC ,method HELLO."
::class XYZ mixinclass Class INHERIT ABC
::method init
say pp(self) "("self~"=="~c2x"): class XYZ ,method INIT."
forward class (super)
::method hello
say pp(self) "("self~"=="~c2x"): class XYZ ,method HELLO."
forward class (super)
------------------ end: test3.rex ----------------
Here is the output of "test1.rex":
==================================================
Start of main program...
[a XYZ] (5C97F11F): class XYZ ,method INIT.
[a XYZ] (5C97F11F): class ABC ,method INIT.
[a XYZ] (5C97F11F): class XYZ ,method HELLO.
[a XYZ] (5C97F11F): class ABC ,method HELLO.
then the output of "test2.rex":
==================================================
Start of main program...
[The MnO class] (1EACF11F): class XYZ ,method INIT.
[The MnO class] (1EACF11F): class ABC ,method INIT.
[The MnO class] (1EACF11F): class XYZ ,method HELLO.
[The MnO class] (1EACF11F): class ABC ,method HELLO.
==> then the output of "test3.rex":
==================================================
Start of main program...
class-object: [The TEST class], the class object's
metaclass: [The XYZ class]
invoking the class method 'HELLO':
[The TEST class] (8CABF11F): class XYZ ,method HELLO.
10 - co~hello -- send hello does NOT work anymore
(".test~hello" wouldn't work either)
Error 97 running E:\WUTemp\oorexx\test\minHeri\test3.rex
line 10: Object method not found
Error 97.1: Object "The TEST class" does not understand
message "HELLO"
Hope that helps clarifying the circumstances under which
this error occurs.
Regards,
---rony
Logged In: YES
user_id=662126
Sorry, the given output of "test3.rex" was given incompletely.
==> line invoking "test3.rex" and the resulting output of
"test3.rex":
E:\WUTemp\oorexx\test\minHeri>test3
[The TEST class] (8CABF11F): class XYZ ,method INIT.
[The TEST class] (8CABF11F): class ABC ,method INIT.
[The TEST class] (8CABF11F): class XYZ ,method INIT.
==================================================
Start of main program...
class-object: [The TEST class], the class object's
metaclass: [The XYZ class]
invoking the class method 'HELLO':
[The TEST class] (8CABF11F): class XYZ ,method HELLO.
10 - co~hello -- send hello does NOT work anymore
(".test~hello" wouldn't work either)
Error 97 running E:\WUTemp\oorexx\test\minHeri\test3.rex
line 10: Object method not found
Error 97.1: Object "The TEST class" does not understand
message "HELLO"
Logged In: YES
user_id=1125291
There is an error in this program that is causing the syntax
error. If you comment out the very last line of the program
(the "forward class (super)" in method XYZ.hello), this
works as expected. The FORWARD instruction fails because it
is attempting to invoke the method "HELLO" in the class'
immediate superclass, which is "Class". To forward to an
inherited method, you need to explicitly specify the target
class on the forward.
Once you take that problem into account, everything in this
class object's method dictionary appears exactly as I'd
expect it to be.
Logged In: NO
But it works, if the classes "ABC" and "XYZ" are
specializing the root class "OBJECT"! I.e. the method
resolution order is "XYZ"->"ABC"->"OBJECT". Therefore,
"super" in the context of class "XYZ" refers to class "ABC"
and not "OBJECT", whereas "super" in the context of class
"ABC" refers to class "OBJECT". (cf. "test1.rex") By your
argument as I understand it that shouldn't work either?
The only difference between the two examples is that "CLASS"
is specialized, the classes "ABC" and "XYZ" are/become
therefore metaclasses. The method resolution order therefore
should be "XYZ"->"ABC"->"CLASS"->"OBJECT". This indeed is
what happens in "test2.rex"! It works flawlessly like
"test1.rex": "super" in the context of the now metclass
"XYZ" refers to the class "ABC" and the method resolution
for "INIT" and for "HELLO" works like a charm (as in
"test1.rex" above)!
The troubles now come into play with "test3.rex", where all
of a sudden the behaviour of "test2.rex" is not kept
anymore. Also, this example "test3.rex" demonstrates (I
think) that the metaclass object gets the "INIT"-method sent
twice(!): in the output the "INIT" of "XYZ" is shown twice,
the "INIT" of "ABC" only once instead, yet at the INIT-time
no runtimie error occurs. Then, retrieving the class object
and then sending the class object the "HELLO" message should
allow it to reach the "HELLO" method in the "ABC" class due
to the multiple-inheritance "derouting" of the method
resolution.
Or with other words: once I get at the class object (an
instance of metaclass "XYZ"), I would expect exactly the
same behaviour for that class object's method resolution as
is the case with "test2.rex". There ("test2.rex") it works,
here ("test3.rex"), all of a sudden, it doesn't!
Logged In: YES
user_id=1125291
Finally managed to fix this. Hopefully it was done without
breaking something else.