1

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?

Suma
  • 33,181
  • 16
  • 123
  • 191

1 Answers1

3

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.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • Out of curiosity: is there a reason for this limitation? What kind of evil would happen if arbitrary FunctionN expression were converted to SAM type instances? – Suma Nov 15 '17 at 19:20
  • I don't think anything particularly evil, this is just consistent with Java. It's also what Kotlin documentation says, but not how it actually works, IIRC :) – Alexey Romanov Nov 15 '17 at 22:18