So let's say I want to create a custom function type called ImportFunc that takes in an Int called fileImportID and a string called filename. I can do this pretty easily using a type alias like so:
type ImportFunc = (Int, String) => Unit
The problem is, anybody trying to use this function has no idea what Int and String are actually supposed to be. Is there some way I can write something like:
type ImportFunc = (fileImportID: Int, filename: String) => Unit
When you call a function, you actually call the function's apply method. 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 the arguments's names when doing a call with named parameters, that's necessarily in the apply
method's definition.
It turns out that in Function2
, those arguments are named v1
and v2
. So we can do:
scala> f.apply(v1=123, v2="file.txt")
Importing file #123 (file.txt)
Now let's see if it still works when using the syntactic sugar (in other words when removing the explicit call to apply
):
scala> f(v1=123, v2="file.txt")
Importing file #123 (file.txt)
Nice, it works.
Now of course v1
and v2
is not quite the same as fileImportID
and filename
, but we can fix that with a bit of type refinement:
type ImportFunc = ((Int, String)=>Unit) {
def apply(fileImportID: Int, filename: String): Unit
}
Basically this is just (Int, String)=>Unit
(or in other words Function2[Int, String, Unit]
) but with a redefinition of apply
with our desired argument names.
Let's see this in action:
scala> val f: ImportFunc = doImport _
f: ImportFunc = <function2>
scala> f(fileImportID=123, filename="file.txt")
Importing file #123 (file.txt)
Success!
An important side note: in terms of typing, ImportFunc
is identical to Function2[Int, String, Unit]
, or to any other similar refinement.
This is because argument names are not part of the signature. So in my example f
can still be passed anywhere a Function2[Int, String, Unit]
is expected
(but from that point you won't be able anymore to call it using your custom argument names).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With