Search code examples
scalafunctionimplicitimplicits

Function implicit parameters not any more so after passing it to a higher order function


In Scala you can do things like:

def foo(implicit v: Int) = println(v);
def h(x: Int) = { implicit val i: Int = x; foo }

h(42)
> 42

h call gets foo reference as a closure.

It wouldn't be strange to try passing foo to h as a parameter:

def g(x: Int)(f: Int => Unit) = { implicit val i: Int = x; f }

But it wouldn't work:

g(1)(foo)
> error: could not find implicit value for parameter v: Int

What I think it's happening is that foo gets called as an evaluation of the actual parameter. Is that right?

When passed a function with a normal parameter list (not implicit), the function is not being evaluated:

def foo2(v: Int) = println("Foo2")
g(1)(foo2)
> Int => Unit = <function1>

This is an expected result and foo2 evaluation is not tried as a evaluation of an actual parameter.

Why is foo evaluated as an actual parameter when no implicit values are available to do so?

Same occurs with assignation:

val fooref: Int => Unit = foo
> error: could not find implicit value for parameter v: Int

It is like since Int => Unit doesn't match with a function where the Int parameter is marked as implicit, the compiler discard it as a valid actual parameter and therefore tries to evaluate it. Not finding a declared implicit value to fulfill the call.

If that is the case, what whould be the way of expressing the type of a function with implicit parameters?


Solution

  • Unfortunately, functions cannot have implicit parameters - only methods can.

    In the expression g(1)(foo), foo is converted from a method to a function (also known as eta-expansion). And section 6.26.2 of the Scala Specification states that implicit arguments are applied before eta-expansion.

    See this ticket: implicit methods behave suboptimally when used non-implicitly