Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does calling super in Groovy (version 2.4.5) miss the parent class?

Tags:

groovy

Given the following arrangement of classes:

class GrandParent { 
    String init() { 
        return "GrandParent init, " 
    } 
}

class Parent extends GrandParent { 
    String init() { 
        return super.init() + "Parent init, " 
    } 
}

class ChildInitAndVisit extends Parent { 
    String init() { 
        return super.init() + "Child init" 
    }

    String visit() { 
        return super.init() + "Child visit" 
    } 
}

class ChildVisitOnly extends Parent { 
    String visit() { 
        return super.init() + "Child visit" 
    } 
}

and then using them in this way:

iv = new ChildInitAndVisit()
println "ChildInitAndVisit - calling init() -> ${iv.init()}"
println "ChildInitAndVisit - calling visit() -> ${iv.visit()}"

v = new ChildVisitOnly()
println "ChildVisitOnly - calling visit() -> ${v.visit()}"

I would expect to see:

ChildVisitOnly - calling visit() -> GrandParent init, Parent init, Child visit

as the output of the last println. Instead I see:

ChildVisitOnly - calling visit() -> GrandParent init, Child visit

This is in contrast to the behaviour of the ChildInitAndVisit class and different to the behaviour under older versions of Groovy - I checked 2.3.4.

Is this a Groovy bug? Or should I be doing something different?

like image 963
Bimal Shah Avatar asked Nov 17 '15 18:11

Bimal Shah


2 Answers

In my opinion it is a bug. super.init() in ChildVisitOnly must call Parent#init().

like image 69
blackdrag Avatar answered Oct 23 '22 16:10

blackdrag


I believe this is multi-methods (runtime/dynamic dispatch) behavior of Groovy. At runtime, init() from GrandParent is used instead of init() from Parent.

One way to use it the Java way (compile time dispatch) is to use @CompileStatic on ChildVisitOnly class.

@CompileStatic
class ChildVisitOnly extends Parent { 

    String visit() { 
        return super.init() + "Child visit" 
    } 
}

Above would give the result you expect.

Another approach would be to use init() or this.init() in ChildVisitOnly explicitly instead of @CompileStatic to force the use of init() from Parent.

class ChildVisitOnly extends Parent { 

    String visit() { 
        return init() + "Child visit" 
    } 
}

This obviously deviates from the behavior from Groovy 2.3.4 but I am yet to find a related issue which focuses on this difference. I am curious to see if anybody else can point me to a defect due to which the behavior changed. :)

like image 44
dmahapatro Avatar answered Oct 23 '22 17:10

dmahapatro