Search code examples
scalafunctionsingle-abstract-method

Strange SAM rules with functions


What are exact rules for a function to be considered for Single Abstract Method conversion? In the following code there are two very similar cases, one is compiled, second is not, when compiled with Scala 2.12.4:

trait SAM {
  def apply(a: Int, b: Int): Unit
}

def callSAM(sam: SAM): Unit = {
  sam(0, 1)
}

def iAmSam(f: (Int, Int) => Unit) = {

  def lf(a: Int, b: Int) = f(a, b)

  callSAM(f) // does not work - error:
  //                          type mismatch:
  //                          found (Int, Int) => Unit,
  //                          required SAM

  callSAM(lf) // works. What is the difference?

  callSAM(f(_, _)) // works (lambda)

  callSAM((a, b) => f(a, b)) // works (lambda)
}

What is the reason callSAM(lf) works and callSAM(f) does not? I have found a mention in Scala 2.12 release notes, which says:

Note that only lambda expressions are converted to SAM type instances, not arbitrary expressions of FunctionN type

The lf does not look like lambda expression to me. Were the rules relaxed after 2.12.0? When lf is accepted, why f is not?


Solution

  • f is just an object, and falls exactly under

    arbitrary expressions of FunctionN type

    lf is the name of a method and when used as expression it's a shorthand for lf _ which in turn expands to (x, y) => lf(x, y), which is a lambda expression.