9

I'm learning Programming Paradigms in my University and reading this course material provided by the lecturer that defined a function this way:

val double = (x: Int) => 2 * x
double: Int => Int = <function1>

But from my own studies I found and got used to defining the same function like this:

def d (x: Int) = 2 * x
d: (x: Int)Int

I'm new to Scala. And both definitions give a result of:

res21: Int = 8

Upon passing 4 as the parameter. Now my main question is why would the lecturer prefer to use val to define a function? I see it as longer and not really necessary unless using val gives some added advantages that I don't know of. Besides I understand using val makes some name a placeholder so later in the program, I could mistakenly write val double = 5 and the function would be gone! At this stage I'm quite convinced I learned a better way of defining a function unless someone would tell me otherwise.

theon
  • 14,170
  • 5
  • 51
  • 74
emi
  • 2,830
  • 5
  • 31
  • 53
  • I'm not qualified to say something definitive about Scala, but have you tried to actually do `val double = 5` after the function is defined as `double`? I've got the impression it should be impossible to redefine a name once it is defined. In any case, both `val` and `def` produce the same result here. The difference is merely stylistic. Often, it is more clear to define a function with `def` but sometimes it makes sense to define it with `val`. If you are unsure, I would recommend you go with `def` since it is less likely to cause any confusion. – kqr Oct 26 '13 at 13:55
  • Yes, I did `val double = 5`, typed `double` and got `res24: Int = 5` – emi Oct 26 '13 at 14:00
  • possible duplicate of [Difference between method and function in Scala](http://stackoverflow.com/questions/2529184/difference-between-method-and-function-in-scala) – 0__ Oct 26 '13 at 14:01
  • Also [this question](http://stackoverflow.com/questions/4839537/functions-vs-methods-in-scala). Most of the time, you can use both variants, so it's a stylistic question. I would agree with you to prefer methods, but it's just a preference. – 0__ Oct 26 '13 at 14:02
  • 1
    "`val` makes some name a placeholder"—that doesn't matter, `def d` also introduces a symbol `d` which you could latter shadow by redefining it. In that respect, there is no real difference between the two. – 0__ Oct 26 '13 at 14:08

3 Answers3

14

Strictly speaking def d (x: Int) = 2 * x is a method, not a Function, however scala can transparently convert (lift) methods into Functions for us. So that means you can use the d method anywhere that requires a Int => Int Function.

There is a small overhead of performing this conversion, as a new Function instance is created every time. We can see this happening here:

val double = (x: Int) => 2 * x
def d (x: Int) = 2 * x

def printFunc(f: Int => Int) = println(f.hashCode())

printFunc(double)
printFunc(double)
printFunc(d)
printFunc(d)

Which results in output like so:

1477986427
1477986427
574533740
1102091268

You can see when explicitly defining a Function using a val, our program only creates a single Function and reuses it when we pass as an argument to printFunc (we see the same hash code). When we use a def, the conversion to a Function happens every time we pass it to printFunc and we create several instances of the Function with different hash codes. Try it

That said, the performance overhead is small and often doesn't make any real difference to our program, so defs are often used to define Functions as many people find them more concise and easier to read.

theon
  • 14,170
  • 5
  • 51
  • 74
  • 2
    [Some guy](http://japgolly.blogspot.com.au/2013/10/scala-methods-vs-functions.html) ran a benchmark just recently, showing that "eta-expansion" (lift a method to a function when passing it as an argument) doesn't really incur a performance penalty. – 0__ Oct 26 '13 at 14:27
  • Nice post. I guess there could also be an increase in garbage collection, but I imagine that will be a tiny/non-existent too. – theon Oct 26 '13 at 14:39
5

In Scala, function values are monomorphic (i.e. they can not have type parameters, aka "generics"). If you want a polymorphic function, you have to work around this, for example by defining it using a method:

def headOption[A]: List[A] => Option[A] = {
  case Nil   => None
  case x::xs => Some(x)
}

It would not be valid syntax to write val headOption[A]. Note that this didn't make a polymorphic function value, it is just a polymorphic method, returning a monomorphic function value of the appropriate type.

Ben James
  • 121,135
  • 26
  • 193
  • 155
  • What A refer to? I some time saw **def name[T]()** i don't understand what it is[]() in scala mean – Meas Apr 11 '18 at 11:29
0

Because you might have something like the following:

abstract class BaseClass {
  val intToIntFunc: Int => Int
}

class A extends BaseClass {
  override val intToIntFunc = (i: Int) => i * 2
}

So its purpose might not be obvious with a very simple example. But that Function value could itself be passed to higher order functions: functions that take functions as parameters. If you look in the Scala collections documentation you will see numerous methods that take functions as parameters. Its a very powerful and versatile tool, but you need to get to a certain complexity and familiarity with algorithms before the cost /benefit becomes obvious.

I would also suggest not using "double" as an identifier name. Although legal Scala, it is easy to confuse it with the type Double.

Rich Oliver
  • 6,001
  • 4
  • 34
  • 57