6

If we have a method that accepts an anonymous function A => B as a parameter, we can make A implicit in our invocation.

def impl(a: Int)(f: Int => Int): Int = f(a)

impl(a) { implicit z =>
    ...
}

But can we do this with anonymous functions that have multiple parameters?

def impl(a: Int, b: Int)(f: (Int, Int) => Int): Int = f(a, b)

Ideally, this would work something like:

impl(1, 2) { implicit (a, b) => // wrong
    ...
}

Or

impl(1, 2) { (implicit a, implicit b) => // also wrong
    ...
}

I can work around this using A => B => C, instead:

def impl(a: Int, b: Int)(f: Int => Int => Int): Int = f(a)(b)

impl(1, 2) { implicit a => implicit b =>
    ...
}

But is there a way to do this without currying the functions?

It should be obvious, but Int is just a dummy placeholder here.

5
  • From what I can see here issues.scala-lang.org/browse/SI-1492 , this is discussed only for anonymous functions with a single parameter. Not sure if it is a limitation. Commented Apr 24, 2015 at 15:16
  • On a side note, Intellij says this: It is not allowed to introduce implicit parameter because of incorrect usage count of parameter Commented Apr 24, 2015 at 15:18
  • Yeah, based on that issue, it seems like it's just not possible. Commented Apr 24, 2015 at 15:19
  • Moreover in scala-lang.org/files/archive/spec/2.11/… It just says A named parameter of an anonymous function may be optionally preceded by an implicit modifier. In that case the parameter is labeled implicit But it doesn't say anything on the restriction. Its a mystery. Commented Apr 24, 2015 at 15:27
  • I guess it could potentially lead to ambiguous implicits if the parameter types are the same (as in my example). Commented Apr 24, 2015 at 15:28

1 Answer 1

5

No, it's not possible. From section 6.23 Anonymous Functions of the spec, the anonymous function syntax is:

Expr            ::=  (Bindings | ['implicit'] id | '_') '=>' Expr
ResultExpr      ::=  (Bindings | (['implicit'] id | '_') ':' CompoundType) '=>' Block
Bindings        ::=  '(' Binding {',' Binding} ')'
Binding         ::=  (id | '_') [':' Type]

As you can see, the implicit case is special cased to only have 1 identifier, while the repetitive case Bindings (which uses the repetition syntax {...} of EBNF) precludes use of implicit.

The only added details for implicit in this section are:

A named parameter of an anonymous function may be optionally preceded by an implicit modifier. In that case the parameter is labeled implicit; however the parameter section itself does not count as an implicit parameter section in the sense defined here. Hence, arguments to anonymous functions always have to be given explicitly.

I think that this text should also clarify that this only works for a single parameter (e.g. "A named parameter of an anonymous function that has exactly 1 parameter...")

Of course, the simplest workaround is to eschew the syntactic sugar and rebind the anonymous function parameters to new implicit variables:

impl(a) { (b, c) =>
    implicit val (impB, imbC) = (b, c)
    ...
}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.