Reputation: 228
Given the code below
class Parent {
def mth(p1: Int = 1, p2: Int = 2) = p1 + p2
}
class Child extends Parent{
override def mth(p2: Int = 10, p1: Int = 20) = super.mth(p2, p1)
}
object Main {
def main(args: String[]) = {
val parentRefToChild: Parent = new Child
println(parentRefToChild.mth(p1=1)) // 21
}
}
The output is 21
but I think it should be 11
. And when inspecting the compiled .class file, I found that parentRefToChild.mth(p1=1)
was compiled to parentRefToChild.mth(1, parentRefToChild.mth$default$2())
. How could scala compiler behave this way.
Upvotes: 2
Views: 375
Reputation: 4256
Problem here is that you have changed sequence of parameters in Child
:
override def mth(p2: Int = 10 , p1: Int = 20)
So generated synthetic methods for mth
in Child
class, will be like:
def mth$default$1 = 10 // generated method for p2 in Child
def mth$default$2 = 20 // generated method for p1 in Child
When you call mth
on Parent
class reference, static type checking is used to determine if parameter has default value or not. Here, static type checking will be done on Parent
as parentRefToChild
is of type Parent
.
So, when parentRefToChild.mth(p1=1)
is encountered, at this point compiler does not know that parentRefToChild
is actually holding Child
class instance. It just tries to match mth
's signature from Parent
class. Now, here it sees that value of p1
is provided but p2
is missing and it has default value, it simply replaces parentRefToChild.mth(p1=1)
with:
parentRefToChild.mth(1, parentRefToChild.mth$default$2())
Now at runtime, synthetic method mth$default$2()
is picked from Child
class (as parentRefToChild
holds Child
's instance) which then turns into:
parentRefToChild.mth(1, 20)
Hence you get 21
as output.
Upvotes: 5