When you call a function, you are actually calling the method of applying the function. In other words, given this:
def doImport(fileImportID: Int, filename: String) { println(s"Importing file #$fileImportID ($filename)") }
The following snippet:
val f = doImport _ f(123, "file.txt")
... is just syntactic sugar for:
val f = doImport _ f.apply(123, "file.txt")
If there is a place where the compiler will look for argument names when making a call with named parameters, this is mandatory in the definition of the apply method. It turns out that in Function2 these arguments are called v1 and v2 . Thus, we can do:
scala> f.apply(v1=123, v2="file.txt") Importing file
Now let's see if it works when using syntactic sugar (in other words, when removing the explicit call to apply ):
scala> f(v1=123, v2="file.txt") Importing file
Nice, it works. Now, of course, v1 and v2 not quite the same as fileImportID and filename , but we can fix this with a little refinement of the type:
type ImportFunc = ((Int, String)=>Unit) { def apply(fileImportID: Int, filename: String): Unit }
Basically it is just (Int, String)=>Unit (or, in other words, Function2[Int, String, Unit] ), but with an override of apply with our desired argument names. Let's look at this in action:
scala> val f: ImportFunc = doImport _ f: ImportFunc = <function2> scala> f(fileImportID=123, filename="file.txt") Importing file
Success!
Important note: in terms of input, ImportFunc identical to Function2[Int, String, Unit] or any other similar refinement. This is because argument names are not part of the signature. Therefore, in my example, f can still be passed anywhere a Function2[Int, String, Unit] (but from now on you can no longer call it using your own argument names).