groovy
  1. groovy
  2. GROOVY-3942

Using metaClass to override methods in class hierarchy does not work as expected

    Details

    • Type: Bug Bug
    • Status: Open Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 1.8-beta-1
    • Fix Version/s: None
    • Component/s: groovy-runtime
    • Labels:
      None
    • Environment:
      Windows XP
    • Number of attachments :
      1

      Description

      I've found some strange behaviour when dynamically overriding methods that are called in a class hierarchy, which I think might be a bug. The problem is that when I override a method on a subclass, code in the superclass still calls the original method (note all classes are Groovy ones, I know this wouldn't work with a Java class hierarchy).

      I've isolated it to this sample code:

          class BaseClass {
              def baseClassMethod() {
                  println "BaseClass.baseClassMethod()"
                  internalMethod()
              }
              def internalMethod() {
                 println "    BaseClass.internalMethod()"
              }
          }
      
          class SubClass extends BaseClass {
              def subClassMethod() {
                  println "SubClass.subClassMethod()"
                  internalMethod()
              }
          }
      
          def subClass = new SubClass()
          subClass.metaClass.internalMethod = { -> println ("    (dynamic).internalMethod()")}
          subClass.baseClassMethod()
          subClass.subClassMethod()
      

      ...which gives me the following output...

      BaseClass.baseClassMethod()
      BaseClass.internalMethod()
      SubClass.subClassMethod()
      (dynamic).internalMethod()

      I would have expected that the dynamic version of internalMethod() would be called both times, given that Groovy has dynamic method dispatching.

      Some discussion of this issue took place on the mailing list: http://old.nabble.com/Problems-using-metaClass-to-override-methods-in-class-hierarchy-td26743895.html#a26743895

      The suggestion is that the CallSiteArray.createCallCurrentSite(...) method could check whether the receiver is a sub class of the sender class.

        Activity

        blackdrag blackdrag made changes -
        Field Original Value New Value
        Description I've found some strange behaviour when dynamically overriding methods that are called in a class hierarchy, which I think might be a bug. The problem is that when I override a method on a subclass, code in the superclass still calls the original method (note all classes are Groovy ones, I know this wouldn't work with a Java class hierarchy).

        I've isolated it to this sample code:

            class BaseClass {
                def baseClassMethod() {
                    println "BaseClass.baseClassMethod()"
                    internalMethod()
                }
                def internalMethod() {
                   println " BaseClass.internalMethod()"
                }
            }

            class SubClass extends BaseClass {
                def subClassMethod() {
                    println "SubClass.subClassMethod()"
                    internalMethod()
                }
            }

            def subClass = new SubClass()
            subClass.metaClass.internalMethod = { -> println (" (dynamic).internalMethod()")}
            subClass.baseClassMethod()
            subClass.subClassMethod()

        ...which gives me the following output...

            BaseClass.baseClassMethod()
                BaseClass.internalMethod()
            SubClass.subClassMethod()
                (dynamic).internalMethod()

        I would have expected that the dynamic version of internalMethod() would be called both times, given that Groovy has dynamic method dispatching.

        Some discussion of this issue took place on the mailing list: http://old.nabble.com/Problems-using-metaClass-to-override-methods-in-class-hierarchy-td26743895.html#a26743895

        The suggestion is that the CallSiteArray.createCallCurrentSite(...) method could check whether the receiver is a sub class of the sender class.
        I've found some strange behaviour when dynamically overriding methods that are called in a class hierarchy, which I think might be a bug. The problem is that when I override a method on a subclass, code in the superclass still calls the original method (note all classes are Groovy ones, I know this wouldn't work with a Java class hierarchy).

        I've isolated it to this sample code:
        {code:Java}
            class BaseClass {
                def baseClassMethod() {
                    println "BaseClass.baseClassMethod()"
                    internalMethod()
                }
                def internalMethod() {
                   println " BaseClass.internalMethod()"
                }
            }

            class SubClass extends BaseClass {
                def subClassMethod() {
                    println "SubClass.subClassMethod()"
                    internalMethod()
                }
            }

            def subClass = new SubClass()
            subClass.metaClass.internalMethod = { -> println (" (dynamic).internalMethod()")}
            subClass.baseClassMethod()
            subClass.subClassMethod()
        {ocde}
        ...which gives me the following output...

            BaseClass.baseClassMethod()
                BaseClass.internalMethod()
            SubClass.subClassMethod()
                (dynamic).internalMethod()

        I would have expected that the dynamic version of internalMethod() would be called both times, given that Groovy has dynamic method dispatching.

        Some discussion of this issue took place on the mailing list: http://old.nabble.com/Problems-using-metaClass-to-override-methods-in-class-hierarchy-td26743895.html#a26743895

        The suggestion is that the CallSiteArray.createCallCurrentSite(...) method could check whether the receiver is a sub class of the sender class.
        blackdrag blackdrag made changes -
        Description I've found some strange behaviour when dynamically overriding methods that are called in a class hierarchy, which I think might be a bug. The problem is that when I override a method on a subclass, code in the superclass still calls the original method (note all classes are Groovy ones, I know this wouldn't work with a Java class hierarchy).

        I've isolated it to this sample code:
        {code:Java}
            class BaseClass {
                def baseClassMethod() {
                    println "BaseClass.baseClassMethod()"
                    internalMethod()
                }
                def internalMethod() {
                   println " BaseClass.internalMethod()"
                }
            }

            class SubClass extends BaseClass {
                def subClassMethod() {
                    println "SubClass.subClassMethod()"
                    internalMethod()
                }
            }

            def subClass = new SubClass()
            subClass.metaClass.internalMethod = { -> println (" (dynamic).internalMethod()")}
            subClass.baseClassMethod()
            subClass.subClassMethod()
        {ocde}
        ...which gives me the following output...

            BaseClass.baseClassMethod()
                BaseClass.internalMethod()
            SubClass.subClassMethod()
                (dynamic).internalMethod()

        I would have expected that the dynamic version of internalMethod() would be called both times, given that Groovy has dynamic method dispatching.

        Some discussion of this issue took place on the mailing list: http://old.nabble.com/Problems-using-metaClass-to-override-methods-in-class-hierarchy-td26743895.html#a26743895

        The suggestion is that the CallSiteArray.createCallCurrentSite(...) method could check whether the receiver is a sub class of the sender class.
        I've found some strange behaviour when dynamically overriding methods that are called in a class hierarchy, which I think might be a bug. The problem is that when I override a method on a subclass, code in the superclass still calls the original method (note all classes are Groovy ones, I know this wouldn't work with a Java class hierarchy).

        I've isolated it to this sample code:
        {code:Java}
            class BaseClass {
                def baseClassMethod() {
                    println "BaseClass.baseClassMethod()"
                    internalMethod()
                }
                def internalMethod() {
                   println " BaseClass.internalMethod()"
                }
            }

            class SubClass extends BaseClass {
                def subClassMethod() {
                    println "SubClass.subClassMethod()"
                    internalMethod()
                }
            }

            def subClass = new SubClass()
            subClass.metaClass.internalMethod = { -> println (" (dynamic).internalMethod()")}
            subClass.baseClassMethod()
            subClass.subClassMethod()
        {code}
        ...which gives me the following output...

            BaseClass.baseClassMethod()
                BaseClass.internalMethod()
            SubClass.subClassMethod()
                (dynamic).internalMethod()

        I would have expected that the dynamic version of internalMethod() would be called both times, given that Groovy has dynamic method dispatching.

        Some discussion of this issue took place on the mailing list: http://old.nabble.com/Problems-using-metaClass-to-override-methods-in-class-hierarchy-td26743895.html#a26743895

        The suggestion is that the CallSiteArray.createCallCurrentSite(...) method could check whether the receiver is a sub class of the sender class.
        blackdrag blackdrag made changes -
        Affects Version/s 1.6.2 [ 15151 ]
        Affects Version/s 1.8-beta-1 [ 16013 ]
        Jason Griffith made changes -
        Attachment MetaclassOverrideTest.groovy [ 58074 ]
        blackdrag blackdrag made changes -
        Component/s groovy-runtime [ 16250 ]

          People

          • Assignee:
            Unassigned
            Reporter:
            Alex McManus
          • Votes:
            5 Vote for this issue
            Watchers:
            6 Start watching this issue

            Dates

            • Created:
              Updated: