Why is Scala's behavior in case of overloading with by-name parameters different from the case with by-value parameters?
Asked Answered
C

2

9

Given this Scala code:

object test {

  def byval(a: Int) = println("Int")
  def byval(a: Long) = println("Long")

  def byname(a: => Int) = println("=> Int")
  def byname(a: => Long) = println("=> Long")

  def main(args: Array[String]) {
      byval(5)
      byname(5)
  }
}

the call byval(5) compiles correctly, but byname fails to compile:

ambiguous reference to overloaded definition

Why? I would expect to observe the same behavior for by-value and by-name parameters with respect to overloading… How can it be fixed?

Chadburn answered 1/12, 2010 at 14:0 Comment(0)
P
14

That's because JVM does not support a "by-name" parameter, so Scala has to implement it in another way. => X actually compiles to a Function0[X], which erases to Function0[Object], which makes it impossible for Scala to distinguish two methods that differ only by the expected type of a by-name parameter.

Photogrammetry answered 1/12, 2010 at 14:31 Comment(4)
Thanks Daniel, this explains the why. Now how can this be worked arouned (if at all possible)?Chadburn
@JPP That's a question that has been asked before. One simple way would be to make the first argument mandatory and not part of the vararg. Other methods involve implicit parameters, but I don't recall the exact tricks.Photogrammetry
@JPP: Don't use overloading in this particular case.Joan
scala-programming-language.1934581.n4.nabble.com/…Joan
J
6

Possible workaround without overloading (in addition to what has been said earlier), if you don't want to use different method names:

def byname[A](a: => A)(implicit manifest:Manifest[A]) = 
manifest.erasure match {
   case erasure if(erasure.isAssignableFrom(classOf[Long])) => println("=> Long")
   case erasure if(erasure.isAssignableFrom(classOf[Int])) => println("=> Int")
}
Joan answered 1/12, 2010 at 15:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.