user79074
user79074

Reputation: 5270

How to reference a function that takes varargs

If I define the following function to return a function:

def foo(): (Int*) => String = { is =>
    is.map(_.toString).mkString(", ")
}

And then try to reference it:

val bar = foo()
bar(1, 2, 3)

I get the compiler error

Too many arguments (3) for method apply...

But when I explicitly define the reference type it compiles fine:

val bar2: (Int*) => String = foo()
bar2(4, 5, 6)

Is there any way I can define my function foo() without needing this explicit reference type?

Upvotes: 10

Views: 696

Answers (1)

Travis Brown
Travis Brown

Reputation: 139038

This is a known bug, which was "fixed" in Scala 2.13 by removing the ability to use * in types outside of method signatures at all.

If you only care about pre-2.13 Scala versions, you can use the workaround you've identified—explicitly annotate the function variable with the starred type. If you need to support 2.13, you can do something like this, thanks to Scala's single abstract method syntax:

trait MyVarargsFunc[-A, +B] {
  def apply(is: A*): B
}

val f: MyVarargsFunc[Int, String] = is => is.map(_.toString).mkString(", ")

Or if you want to get really fancy:

trait *=>[-A, +B] { def apply(is: A*): B }

val f: Int *=> String = is => is.map(_.toString).mkString(", ")

And then:

scala> f(1, 2, 3)
res0: String = 1, 2, 3

This will also work on 2.12 (I checked), and it should work on 2.11 with -Xexperimental (and it'll work even on 2.10 or vanilla 2.11 if you instantiate MyVarargsFunc explicitly—you just don't get the nice function literal syntax).

Upvotes: 13

Related Questions