Chris Leishman
Chris Leishman

Reputation: 1798

Scala type inference fails on overloaded methods despite non-conflicting signature

% scala                                                                     
Welcome to Scala 2.12.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_111).
Type in expressions for evaluation. Or try :help.

scala>   trait Op[-Y, -Z, +A, +B] {
     |     def apply(other: (Y, Z)): (A, B)
     |   }
defined trait Op

scala>   implicit class RichTuple2[+A, +B](t: (A, B)) {
     |     def ~~~(other: Int): (A, B) = ???
     |     def ~~~[RA, RB](other: Op[A, B, RA, RB]): (RA, RB) = other.apply(t)
     |   }
defined class RichTuple2

scala>   def swap[A, B] = new Op[A, B, B, A] {
     |     override def apply(other: (A, B)) = (other._2, other._1)
     |   }
swap: [A, B]=> Op[A,B,B,A]

scala> (1, "foo") ~~~ swap
<console>:14: error: overloaded method value ~~~ with alternatives:
  [RA, RB](other: Op[Int,String,RA,RB])(RA, RB) <and>
  (other: Int)(Int, String)
 cannot be applied to (Op[Nothing,Nothing,Nothing,Nothing])
       (1, "foo") ~~~ swap

If I remove the first ~~~(other: Int) method, then it works:

scala>   trait Op[-Y, -Z, +A, +B] {
     |     def apply(other: (Y, Z)): (A, B)
     |   }
defined trait Op

scala>   implicit class RichTuple2[+A, +B](t: (A, B)) {
     |     def ~~~[RA, RB](other: Op[A, B, RA, RB]): (RA, RB) = other.apply(t)
     |   }
defined class RichTuple2

scala>   def swap[A, B] = new Op[A, B, B, A] {
     |     override def apply(other: (A, B)) = (other._2, other._1)
     |   }
swap: [A, B]=> Op[A,B,B,A]

scala> (1, "foo") ~~~ swap
res0: (String, Int) = (foo,1)

The question is why type inference and method selection fails in this case? The method ~~~(other: Int) takes a parameter that isn't at all related to the type of swap (with is an Op type). And is anyone aware of a workaround?

Upvotes: 0

Views: 52

Answers (1)

Ziyang Liu
Ziyang Liu

Reputation: 810

scalac sometimes has trouble finding the right implicits or inferring the right types when one mixes implicits with overloading.

There are several jira tickets on this topic, and this particular one: SI-9523, appears to be the same problem as the one in your question.

In your case scalac is unable to infer the type arguments for swap when ~~~ is overloaded, so annotating it with swap[Int, String] should work.

Overloading is generally discouraged in Scala (see Why "avoid method overloading"?) and (http://www.wartremover.org/doc/warts.html), so the best solution is to avoid overloading.

Upvotes: 1

Related Questions