Tech and stuff
Scala has a concept of functions and method definitions. These two concepts are often confused and it’s not always clear when to use which.
Consider this example.
Simple method:
def m1(x: Int) = x + x
m1(2) // 4
Simple function:
val f1 = (x: Int) => x + x
f1(2) // 4
Both m1
and f1
are called the same way and will produce the same result but when you look closer you will see that these are two different things.
f1 // Int => Int = <function1>
m1 // error: missing argument list for method m1...
Calling f1
without argument will give us the signature of anonymous function.
Our anonymous functions is actually an instance of Function1[Int, Int]
that means a function with 1 parameter of type Int and return value of type Int.
f1.isInstanceOf[Function1[Int, Int]] // Boolean = true
When calling m1
we will get an error. This is because m1
is not a value, it is a method, something that will produce a value when you call it by providing all required arguments.
Method can be converted into a proper function (often referred to as lifting) by calling method with underscore “_” after method name.
val f2 = m1 _ // Int => Int = <function1>
Alternatively you can supply a type and compiler will know what to do.
val f2: Int => Int = m1 // Int => Int = <function1>
Above method to function conversions will always create a new instance of Function1[Int, Int]
which is an important observation.
Let’s consider following example. We are creating a sequence of tuples with type (Int, Int => Int)
. For each tuple we decided to convert our previously defined method into a function. The following will create 10 instances of a function that does the same thing.
for (i <- 0 until 10) yield i -> m1 _
Better approach would be to pass the same instance of the function for each tuple and avoid allocating memory for each instance as in previous approach.
for (i <- 0 until 10) yield i -> f1
f1.compose(f2)(2)
def m1(age: Int = 2) = ...