SuspiciousPineapple
SuspiciousPineapple

Reputation: 95

Function Overloading Mechanism

class X
class Y extends X
class Z extends Y
class M {
  def f(x: X): String = "f with X at M"
  def f(x: Y): String = "f with Y at M"
}
class N extends M {
  override def f(x: Y): String = "f with Y at N"
  def f(x: Z): String = "f with Z at N"
}

val z: Z = new Z
val y: Y = z
val x: X = y
val m: M = new N
println(m.f(x))
// m dynamically matches as type N and sees x as type X thus goes into class M where it calls "f with X at M"
println(m.f(y))
// m dynamically matches as type N and sees y as type Y where it calls "f with Y at N"
println(m.f(z))
// m dynamically matches as type N and sees z as type Z where it calls "f with Z at N"

Consider this code, I don't understand with the final call println(m.f(z)) doesn't behave as I wrote in the comments - is there a good resource for understanding how overloading works in Scala?

Thank!

Upvotes: 1

Views: 71

Answers (3)

Niks
Niks

Reputation: 4832

When you do this

val m: M = new N

It means that m is capable of doing everything that class M can. M has two methods - first which can take X, other Y.

And hence when you do this

m.f(z)

Runtime is going to search for a method which can accept z (of type Z). The method in N is not a candidate here because of two reasons

  1. The reference is of type M
  2. Your N does not override any method of M which can accept an argument of type Z. You do have a method in N which can accept a Z but that's not a candidate because it's not overriding anything from M
  3. The best match is f in M which can accept a Y this is because Z ISA Y

You can get what your last comment says if

  1. You define a method in M which takes argument of type Z and then you override it in N
  2. You instantiate a val of type N e.g: val m : N = new N

I think the existing questions on SO already elaborate this point.

Upvotes: 0

Sergii Lagutin
Sergii Lagutin

Reputation: 10661

Firstly overloading in Scala works the same as in Java.

Secondly, it's about static and dynamic binding. Let's find out what compiler see. You have m: M object. Class M has f(X) and f(Y) methods. When you call m.f(z) compiler resolves that method f(Y) should be called because Z is subclass of Y. It's a very important point: compiler doesn't know real class of m object that's why it knows nothing about method N.f(Z). And it's called static binding: compiler resolves method's signature. Later, in runtime, dynamic binding happens. JVM knows real class of m and it calls f(Y) which is overloaded in Z. Hope my explanations are clearly enough to understand.

Upvotes: 2

SMS
SMS

Reputation: 84

class x
class Y extends X
class Z extends Y
class M {
  def f(x: X): String = "f with X at M"
  def f(x: Y): String = "f with Y at M"
}
class N extends M {
  override def f(x: Y): String = "f with Y at N"
  def f(x: Z): String = "f with Z at N"
}

val z: Z = new Z
val y: Y = z
val x: X = y
val m: M = new N
println(m.f(x))
// m dynamically matches as type N and sees x as type X thus goes into class M where it calls "f with X at M"
println(m.f(y))
// m dynamically matches as type N and sees y as type Y where it calls "f with Y at N"
println(m.f(z))
// m dynamically matches as type N and sees z as type Z where it calls "f with Z at N"

Because the function will be overloaded on N.so N is depends on m.f(y) .finally it is related with x and y that is reason z function will call

Upvotes: 0

Related Questions