I am watching Runar Bjarnason present Functional Programming for Beginners, and at 14:45 he defines a method:
def isDivisibleBy(k: Int): Int => Boolean = i => i % k == 0
and a function:
val isEven = isDivisibleBy(2)
What are the pros and cons of defining isEven
as a function rather than a method?
I have read Scala Functions vs Methods as well as Difference between method and function in Scala, and I understand the semantic differences, but I wonder if there's some deeper reason in this case why a function might or might not be preferable to using a method:
def isEven = isDivisibleBy(2)
A function is a set of instructions or procedures to perform a specific task, and a method is a set of instructions that are associated with an object.
A Scala method is a part of a class which has a name, a signature, optionally some annotations, and some bytecode where as a function in Scala is a complete object which can be assigned to a variable. In other words, a function, which is defined as a member of some object, is called a method.
Here's a simple rule of thumb: if the code acts upon a single instance of an object, use a method. Even better: use a method unless there is a compelling reason to write it as a function. Don't over think it.
Here, Scala function is first-class value. Scala also has methods, but these differ only slightly from Scala function. A method belongs to a class; it has a name, a signature, [optionally, ] some annotations, and some bytecode. A function is a complete object that we can store in a variable.
Under the hood, there are other differences between functions and methods. Generally, a plain method generated less overhead than a function (which technically is an object with an apply
method).
However, if you try not to care about those differences and think of def
, val
and var
as fields with different semantics, then it’s simply that def
evaluates every time it gets called while val
evaluates only once.
So, a val isEven = isDivisibleBy(2)
should call isDivisibleBy(2)
during its definition and assign the result of isDivisibleBy(2)
. E.g. it replaces the k
in
def isDivisibleBy(k: Int): Int => Boolean = i => i % k == 0
with 2
and assigns the result of the final expression (in this case there is only one expression):
val isEven: Int => Boolean = i => i % 2 == 0
def isEven
on the other hand does no such evaluation and results in a call to isDivisibleBy(2) every time.
That means, later, when you execute the code, isEven(11)
generates in case of a val
11 % 2 == 0
and in case of a def
, you’ll have
isDivisibleBy(2)(11)
and only after evaluating isDivisibleBy
you’ll get the result.
You can add some debug code to isDivisibleBy
to see the difference:
def isDivisibleBy(k: Int): Int => Boolean = { println("evaluating isDivisibleBy") i => i % k == 0 }
I'd like to address another point here. This defines isEven
as a method:
def isEven = isDivisibleBy(2)
And this defines isEven
as a method as well:
val isEven = isDivisibleBy(2)
In both cases, isEven
is a method which, when called, return a function.
In the first case, isDivisible(2)
is called every time isEven
is called. For example, this calls isDivisible(2)
three times:
def isEven = isDivisibleBy(2) List(1,2,3).filter(isEven)
In the second case, isDivisible(2)
is called once (at construction time, or when that line in a definition is executed), and that value is retrieved every time isEven
is called. The following example calls isDivisible(2)
one time only:
val isEven = isDivisibleBy(2) List(1,2,3).filter(isEven)
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