I have this class in Scala:
object Util {
class Tapper[A](tapMe: A) {
def tap(f: A => Unit): A = {
f(tapMe)
tapMe
}
def tap(fs: (A => Unit)*): A = {
fs.foreach(_(tapMe))
tapMe
}
}
implicit def tapper[A](toTap: A): Tapper[A] = new Tapper(toTap)
}
Now,
"aaa".tap(_.trim)
doesn't compile, giving the error
error: missing parameter type for expanded function ((x$1) => x$1.trim)
Why isn't the type inferred as String
? From the error it seems that the implicit conversion does fire (otherwise the error would be along the lines of "tap
is not a member of class String
"). And it seems the conversion must be to Tapper[String]
, which means the type of the argument is String => Unit
(or (String => Unit)*
).
The interesting thing is that if I comment out either of tap
definitions, then it does compile.
Both overloads of
tap
are potentially applicable (based on the 'shape' of the arguments, which accounts for the arity and type constructors FunctionN).So the typer proceeds as it would with:
and fails.
A smarter algorithm could take the least upper bound of the corresponding parameter type of each alternative, and use this as the expected type. But this complexity isn't really worth it, IMO. Overloading has many corner cases, this is but another.
But there is a trick you can use in this case, if you really need an overload that accepts a single parameter: