Menu

#2 Multiple inheritance not set up correctly for metaclasses

v3.0
closed
nobody
9
2012-08-14
2004-11-14
No

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.

Discussion

  • Rony G. Flatscher

    Contains program and output

     
  • Rick McGuire

    Rick McGuire - 2005-01-20

    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.

     
  • Rony G. Flatscher

    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

     
  • Rony G. Flatscher

    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"

     
  • Rick McGuire

    Rick McGuire - 2005-01-26

    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.

     
  • Nobody/Anonymous

    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!

     
  • Rick McGuire

    Rick McGuire - 2005-01-27

    Logged In: YES
    user_id=1125291

    Finally managed to fix this. Hopefully it was done without
    breaking something else.

     

Anonymous
Anonymous

Add attachments
Cancel