9.4 Functions Versus Methods
So far in this book, the words function and method have been used almost interchangeably. It is now time to discuss differences between the two. Methods are often defined as being functions associated with a target object: x.m(y), which invokes method m on object x with argument y, is not much different from f(x,y), which calls a function f on x and y. This way of differentiating methods from functions is premised on them being mechanisms used to encapsulate behaviors—blocks of code—which both methods and functions are.
However, the story somewhat changes once functions become values. A more meaningful difference between methods and functions in the context of this book is that functions are values in functional programming, while methods are not objects in object-oriented programming. In a hybrid language like Scala, functions are objects; methods are not. Instead of the function literal (temp: Int) => temp > 90, you could build a regular object explicitly. This object would implement the type Function:
Scala
object GreaterThan90 extends Function[Int, Boolean]: def apply(x: Int): Boolean = x > 90
The notation Int => Boolean is syntactic sugar for the type Function[Int, Boolean]. This type defines a method apply, which is invoked when the function is applied. The expression temps.find(GreaterThan90) could replace temps.find(temp => temp > 90) to perform the same computation.4 GreaterThan90 is an object—which defines a function—not a method. In contrast,
Scala
def greaterThan90(x: Int): Boolean = x > 90
defines a method greaterThan90, not a function.
But then, the plot thickens. We did write temps.find(greaterThan90) earlier to search a list of temperatures, as if greaterThan90 were an object, which it is not. This is possible because the language implements bridges between methods and functions. In Section 2.5, we discussed extension methods, a mechanism to make a function appear as a method. Here, what we need is a conversion in the opposite direction so that we can use a method as a function.
The fancy name for this is λ-conversion. In λ-calculus, it states the equivalence between f and x. f x. In plainer terms, you can think of it as an equivalence between greaterThan90 and x => greaterThan90(x). As units of computation, both perform the same task of asserting whether an integer is greater than 90. Given that the argument of find must have type Int => Boolean, and greaterThan90 is a method from Int to Boolean, the intent of the expression temps.find(greaterThan90) is pretty clear, and the compiler is able to insert the necessary λ-conversion.
Other languages offer similar bridges to create a function out of a method, sometimes by relying on a more explicit syntax. In Java, for instance, a lambda expression x -> target.method(x) can be replaced with a method reference target::method. Kotlin uses a similar syntax.