59

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)
Community
  • 1
  • 1
earldouglas
  • 13,265
  • 5
  • 41
  • 50
  • Just think of it in the equivalent Java (the Scala Functions vs. Methods does a good job of that) and how it fits into the run-time. That is a good bit of the reason for one approach over the other. Also note that scope of `def` is important as it's not the same everywhere (it's only a "method" -- implementation details aside -- at the class-level). –  Jan 29 '11 at 22:15

4 Answers4

75

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
}
Debilski
  • 66,976
  • 12
  • 110
  • 133
  • 1
    What about the difference between `def` at the class-level and vs `def` inside a method? +1 as this is a nice answer (although every-time a function is applied -- e.g. in a `val` it will be called -- it's just a detail that methods can be invoked without explicit parens), but it would be nice to capture those differences (and the meaning of "method") as well. –  Jan 29 '11 at 22:23
  • dumb question: what does the `Boolean = ` do there ? I am new to Scala. :) – David Lin Apr 26 '17 at 06:56
  • Does this mean the calling the isEven function will be faster can calling the isEven method? This is the advantage of functions over methods? – CyberPlayerOne Jan 15 '18 at 08:53
23

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)
Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • 4
    As far as I know, `val` does not define a method. Maybe you mean it's translated to a method in java byte code for some reason (although I don't see why that would be the case). I would think that it is simply a reference to the function object. After all you can just pass the reference around as with other objects. – herman Aug 03 '14 at 13:20
7

I think that the main pro of defining the function isEven as val is to show to audience that the function can be defined this way. Then it's clear, that a function is just an object like everything else in scala. But in the world of non-demonstrating programming, there's no need to write functions as vals.

ryskajakub
  • 6,351
  • 8
  • 45
  • 75
  • It's not a function definition there but an application of a method with a function result: it shows that a function (Int => Boolean) can be stored/treated as a normal object. `val square = (x) => x * x` would be a definition, which also shows the same thing. The subtle nuances between the two (**methods which are object-bound and allow overloading and overriding** (in Java terms) and **functions that are not methods**) are where it becomes "interesting". –  Jan 29 '11 at 22:08
  • I have vague understanding of what `function definition` is, because it's pretty hard to google :-), so I'm using it in an intuitive way. How is `val square...` different? It also accepts an argument and creates a function that is returning an object by applying `*` method to `x`. I tried to read the question thoroughly and answer this particular question. "in this case" is crucial, the question is mentioning a man talking at presentation and his point was imho to show different way of "treating" methods/functions, the question wasn't about nuances between method and functional object. – ryskajakub Jan 30 '11 at 00:18
  • A method if an artifact of Java (perhaps Scala would have them if not a part of Java) -- objects have *methods* (these are defined with `def` in the class-level). Functions in Scala are just a special form of an object (see FunctionN, etc) that have an `apply` method (`def` inside a function are *not methods* -- actually, they can be/are implemented as such, but that's an implementation detail as this is not exposed). Scala just makes turning a *method* into a *function* (or storing a *function* in a variable) trivial. I have not seen this distinction addressed in any answer. –  Jan 30 '11 at 20:34
  • @coubeatczeach In the form of the function definition (`val f = (x) => x`) a new function object is explicitly created (`(x) => x`) and assigned (even if the variable is not re-assignable). The the `def` form (inside a function this is **not a method** -- implementation details aside) does NOT imply creation of an explicit function object (and in current implementations it does not, see the accepted answer). –  Jan 30 '11 at 20:40
  • @coubeatczeach I say all this because the question refers to `def` as being a method and does not specify a scope. Just trying to add a note (that has grown out of hand) on the question. Happy coding. –  Jan 30 '11 at 22:09
3

The method def isDivisibleBy(k: Int): Int => Boolean returns a function which takes an Int (i) as parameter and returns a Boolean (i % k == 0).

val isEven = isDivisibleBy(2) on the other hand is a field into which the function returned by isDivisibleBy(2) is stored. If you use def instead of val then the isDivisibleBy method would be called every time the isEven method is called, but now it's called only once and the result is stored in the field.

You could achieve the same result by writing def isEven(i: Int): Boolean = i % 2 == 0

I think the point of the example is that you can have functions which return other functions, and you can store the functions as objects, and then call them as if they were traditionally defined methods. The above code is also quite similar to currying, so that might also be one thing demonstrated by the example (although it doesn't use Scala's syntax for currying).

Esko Luontola
  • 73,184
  • 17
  • 117
  • 128