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
    • 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

      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

        Alex McManus created issue -
        Jochen Theodorou 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.
        Jochen Theodorou 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.
        Jochen Theodorou made changes -
        Affects Version/s 1.8-beta-1 [ 16013 ]
        Affects Version/s 1.6.2 [ 15151 ]
        Jason Griffith made changes -
        Attachment MetaclassOverrideTest.groovy [ 58074 ]
        Jochen Theodorou made changes -
        Component/s groovy-runtime [ 16250 ]
        Mark Thomas made changes -
        Project Import Sun Apr 05 13:32:57 UTC 2015 [ 1428240777691 ]
        Mark Thomas made changes -
        Workflow jira [ 12732902 ] Default workflow, editable Closed status [ 12744748 ]
        Mark Thomas made changes -
        Project Import Mon Apr 06 02:11:23 UTC 2015 [ 1428286283443 ]
        Mark Thomas made changes -
        Workflow jira [ 12967491 ] Default workflow, editable Closed status [ 12975218 ]

          People

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

            Dates

            • Created:
              Updated:

              Development