Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implicit method to function conversion doesn't work when passed as argument?

Tags:

scala

I might be missing something but I came across a pattern that surprisingly doesn't work.
Here it is:

object A {
  def bar(func: (Int, Int) => Int): Int = 2
  def bar(func: Int => Int): Int = 3
  def foo(func: Int => Int): Int = 4
}

def f(n: Int) : Int = n + 1
val g: Int => Int = f

A.foo(f) // works fine
A.bar(f) // doesn't work
A.bar(g) // but this works

The compiler ask me to explicitly apply the method fin order to pass it (writing f _) :
Unapplied methods are only converted to functions when a function type is expected.

I don't get why the conversion is implicitly made when passing f to A.foo but not when passed to A.bar. It might be related to the fact that bar has two overloads but I'm not sure why ?

I'm using scalac with Scala 2.12.8.

like image 595
skaaj Avatar asked Sep 24 '19 12:09

skaaj


1 Answers

The error message points you in the right direction: as a method, f is not directly equivalent to a value of type Int => Int, even though they are similar. In order to pass it as an argument, f needs to be converted to a value, which is often, but not always done implicitly.

When you declare val g = f _, or use A.bar(f _) you explicitly convert the method to a value.

Because the bar method is overloaded, the compiler is unsure which type you are converting f to (is it Int => Int or (Int,Int) => Int?). To avoid any surprise, it asks you for an explicit conversion. You can also make it compile using A.bar(f: Int => Int), because that lifts the ambiguity by explicitly selecting one of the bar definitions.

The compiler might attempt to reason about this because you're passing a Int => Int and the implicit method->value lifting can only happen if you mean to give it to bar(Int => Int), but in this case it just doesn't. There might be a technical reason for this, like the compiler not attempting to combine overloads resolutions and implicit lifting because of combinatorial explosion. I would consider it a minor limitation of the compiler, which is easily circumvented by being more explicit. More explicit is often better!

As linked in the comments by @slouc, more technical details on this issue are available here.

like image 168
francoisr Avatar answered Oct 19 '22 18:10

francoisr