Scala: The Differences Between `val` and `def` When Creating Functions

This is a page from my book, Functional Programming, Simplified

The main goals for this lesson are:

• Discuss the differences between `val` and `def` “functions”
• Demonstrate the differences between `val` and `def` “functions”

Background

For the most part — maybe 98% of the time — the differences between defining a “function” using `def` or `val` aren’t important. As I can personally attest, you can write Scala code for several years without knowing the differences. As long as you’re able to define a `val` function or `def` method like this:

``````val isEvenVal = (i: Int) => i % 2 == 0
def isEvenDef(i: Int) = i % 2 == 0``````

and then pass them into the `filter` method of a `List`, like this:

``````scala> val xs = List(1,2,3,4)
xs: List[Int] = List(1, 2, 3, 4)

scala> xs.filter(isEvenVal)     //val
res0: List[Int] = List(2, 4)

scala> xs.filter(isEvenDef)     //def
res1: List[Int] = List(2, 4)``````

the differences between them rarely seem to matter.

But as you become a more advanced Scala developer — and as you see the code that some Scala/FP developers like to write — knowing the differences between `val` functions and `def` methods can be helpful, and in some cases it may be essential to understand how code works.

`case` expressions in functions

One example of where this is essential is when Scala/FP developers use `case` expressions to define functions, like this:

``````val f: (Any) => String = {
case i: Int => "Int"
case d: Double => "Double"
case _ => "Other"
}``````

When I saw code like this for the first time I thought, “How can that possibly work? There’s no `match` before the `case` statements, and the definition also don’t show any input parameters defined ... how can this work?”

The answer is that this function does compile and it does work, yielding the results that you’d expect from the `case` expressions:

``````f(1)     // Int
f(1d)    // Double
f(1f)    // Other
f("a")   // Other``````

But why this works can be a mystery — a mystery I’ll resolve in this lesson.

Terminology in this lesson

While `def` is technically used to define a method, in this section I’ll often refer to it as a function. Furthermore, I’ll use the terms “function created with `val`” and “function created with `def`” — or more concisely, “`val` function” and “`def` function” — when I want to be clear about what I’m referring to.

A quick summary of the differences between `val` and `def` functions

To get started, here’s a quick summary of the differences between `val` and `def` functions.

`val` functions

There are a few different ways you can write a `val` function, but a common way to write them looks like this:

``val add = (a: Int, b: Int) => a + b``

A `val` function has these attributes:

• It is 100% correct to use the term “function” when referring to it.
• `add` is created as a variable, in this case as a `val` field.
• Under the hood, the Scala compiler implements this specific example as an instance of the `Function2` trait.
• `val` functions are concrete instances of `Function0` through `Function22`.
• Because `val` functions are instances of `Function0` through `Function22`, there are several methods available on these instances, including `andThen`, `compose`, and `toString`.
• As shown earlier, `val` functions can use `case` expressions without a beginning `match`.

Note that you can manually define functions using syntax like this:

``val sum = new Function2[Int, Int, Int] { ...``

That’s rarely done, but I’ll fully demonstrate that syntax later in this lesson so you can learn more about how things work under the covers.

Because `add` is a true variable (a `val` field), you can examine it in the REPL, like this:

``````scala> add
res0: (Int, Int) => Int = <function2>``````

Note that the `add` function isn’t invoked; the REPL just shows its value.

`def` functions

What I call a “`def` function” looks like this:

``def add(a: Int, b: Int) = a + b``

It has these attributes:

• It is not 100% correct to use the term “function” when referring to it. Technically, it is not a function.
• It is a method that needs to be defined within a `class` or `object`.
• As a method in a class:
• It has access to the other members in the same class.
• It’s passed an implicit reference to the class’s instance. (For example, when the `map` method is called on a `List`, `map` has an implicit reference to the `this` object, so it can access the elements in the instance’s `List`.)
• When you write a `def`, you can specify parameterized (generic) types, like this:

def fooA: String = ???

Finally, note that when you define `add` like this in the REPL:

``def add(a: Int, b: Int) = a + b``

you can’t examine its value in the REPL in the same way you could with a `val` function:

``````scala> add
<console>:12: error: missing arguments for method add;
follow this method with `_' if you want to treat it as a
partially applied function
^``````

Converting methods to functions

As a final note in this initial summary, you can convert a `def` method into a real `val` function. You can do this manually yourself, and the Scala compiler also does it automatically when needed. This feature is called, “Eta Expansion,” and I show how it works in another appendix in this book.

More details

I’ll show many more details in this lesson — for instance, I’ll show decompiled examples of `val` and `def` functions — but I wanted to start with these key points.

Why a `val` function can use a `case` expression without a beginning `match`

I noted at the beginning of this lesson that you can write a `val` function using `case` expressions without a beginning `match` keyword, like this:

``````val f: (Any) => String = {
case i: Int => "Int"
case d: Double => "Double"
case _ => "Other"
}``````

The reasons this syntax works are:

1. A block of code with one or more `case` expressions is a legal way to define an anonymous function.
2. As I mention in the “Functions are Values” lesson, when you create a `val` function, all you’re really doing with code like this is assigning a variable name to an anonymous function.

To support that first statement, Section 15.7 of Programming in Scala states:

“A sequence of cases in curly braces can be used anywhere a function literal can be used.”

Here are two examples that show how you can use a `case` expression as an anonymous function. First, a modulus example:

``````scala> List(1,2,3,4).filter({ case i: Int => i % 2 == 0 })
res0: List[Int] = List(2, 4)``````

Next, a “string length” example:

``````scala> val misc = List("adam", "alvin", "scott")
misc: List[String] = List(adam, alvin, scott)

scala> misc.map({ case s: String => s.length > 4 })
res1: List[Boolean] = List(false, true, true)``````

If you read the Scala Cookbook, you may also remember this example from Section 9.8 on Partial Functions:

``````scala> List(0,1,2) collect { case i: Int if i != 0 => 42 / i }
res2: List[Int] = List(42, 21)``````

This example works because (a) the `case` expression creates an anonymous function, and (b) the `collect` method works with Partial Functions. Contrast that with `map`, which explodes with a `MatchError` when it’s used with that same `case` expression:

``````scala> List(0,1,2) map { case i: Int if i != 0 => 42 / i }
scala.MatchError: 0 (of class java.lang.Integer)``````

The `val` function syntax

As I noted earlier, a `val` function is simply a variable name that’s assigned to a function literal. To demonstrate this, here’s the function literal: And here’s the variable name being assigned to the function literal: By contrast, if you want to write the same code using `def`, it would be defined like this:

``def isEven(i: Int): Boolean = i % 2 == 0``

Decompiling a `def` method

As you might suspect, a `def` method in a Scala class is compiled into a similar method on a Java class. To demonstrate this, if you start with this Scala class:

``````class DefTest {
def add1(a: Int) = a + 1
}``````

you can then compile it with `scalac`. When you compile it with the following command and look at its output, you’ll find that there’s still a method in a class:

``````\$ scalac -Xprint:all DefTest.scala

package <empty> {
class DefTest extends Object {
def add1(a: Int): Int = a.+(1);  //<-- the method
def <init>(): DefTest = {
DefTest.super.<init>();
()
}
}
}``````

If you further disassemble the resulting .class file with `javap`, you’ll see this output:

``````\$ javap DefTest

Compiled from "DefTest.scala"
public class DefTest {
public int add1(int);   //<-- the method
public DefTest();
}``````

Clearly, `add1` is a method in the bytecode for the `DefTest` class.

Finally, if you completely decompile the .class file back into Java source code using Jad, you’ll again see that `add1` is a method in the Java version of the `DefTest` class:

``````public class DefTest {

return a + 1;
}

public DefTest() {}

}``````

By all accounts, creating a Scala `def` method creates a standard method in a Java class.

Decompiling a `val` function

A Scala function that’s created with `val` is very different than a method created with `def`. While `def` creates a method in a class, a function is an instance of a class that implements one of the `Function0` through `Function22` traits.

To see this, create a class named ValTest.scala with these contents:

``````class ValTest {
val add1 = (a: Int) => a + 1
}``````

When you compile that class with `scalac`, you’ll see that it creates two .class files:

``````ValTest.class
ValTest\$\$anonfun\$1.class``````

When you decompile ValTest.class with `javap` you see this output:

``````\$ javap ValTest

Compiled from "ValTest.scala"
public class ValTest {
public ValTest();
}``````

That output shows that `add1` is defined as a method in the `ValTest` class that returns an instance of the `Function1` trait.

Back in the good old days (around Scala 2.8) it was much easier to look at this code to see what’s going on, but these days I find it hard to see what’s going on in these class files using `javap`, so I revert to decompiling them with Jad. Decompiling ValTest.class converts the class file to Java source code:

``````import scala.Function1;
import scala.Serializable;
import scala.runtime.BoxesRunTime;

public class ValTest {

}

public ValTest() {}

private final Function1 add1 = new Serializable() {

public final int apply(int a) {
return apply\$mcII\$sp(a);
}

public int apply\$mcII\$sp(int a) {
return a + 1;
}

public final volatile Object apply(Object v1) {
return ``````

BoxesRunTime.boxToInteger(apply(BoxesRunTime.unboxToInt(v1))); }

``````        public static final long serialVersionUID = 0L;

}
;
}``````

While this code is still hard to interpret, a couple of things are clear:

• `add1()` is a method in the `ValTest` class.
• The `add1()` method returns the `add1` instance.
• The `add1` instance is created by making an anonymous class instance of `scala.Serializable`.
• The `add1` instance has an `apply` method that calls another method named `apply\$mcII\$sp`, and that second method contains the body of the original function, `a + 1`.

What isn’t clear from this code unless you dig pretty deep into it is that the original Scala function:

``val add1 = (a: Int) => a + 1``

creates `add1` as an instance of `Function1`. It’s easier to see this in the REPL.

Looking at `val` functions in the REPL

When you put this function in the Scala REPL, you see this result:

``````scala> val add1 = (a: Int) => a + 1
add1: Int => Int = <function1>``````

This shows that `add1` is an instance of `Function1`. If you’re not comfortable with the REPL output, one way you can prove this is to show that `add1` is an object with an `apply` method:

``````scala> add1.apply(2)
res0: Int = 3``````

To be clear, when you call `add1(2)`, this is exactly what happens under the hood. Scala has some nice syntactic sugar that hides this from you — and makes your code easy to read — but this is what really happens under the hood.

You can further demonstrate this by looking at the `Function1` Scaladoc. There you’ll see that any class that implements `Function1` must have these three methods:

• `andThen`
• `compose`
• `toString`

This code demonstrates that `add1` has the `andThen` method:

``````scala> (add1 andThen add1)(5)
res1: Int = 7``````

This shows that `compose` is available on `add1`:

``````scala> (add1 compose add1)(10)
res2: Int = 12``````

`toString` also works:

``````scala> add1.toString
res3: String = <function1>``````

Finally, because `add1` takes an `Int` input parameter and returns an `Int`, it is implemented as an instance of `Function1[Int,Int]`. You can also demonstrate this in the REPL:

``````scala> add1.isInstanceOf[Function1[Int,Int]]
res4: Boolean = true``````

Clearly, `add1` is an object of type `Function1`.

Trying that on a `def` method

By comparison, if you try to call `toString` on a method created with `def`, all you get is an error:

``````scala> def double(a: Int) = a * 2
double: (a: Int)Int

scala> double.toString
<console>:12: error: missing arguments for method double;
follow this method with `_' if you want to treat it as a
partially applied function
double.toString
^``````

As mentioned, a `def` is not really a `val`, it just works like a `val` when you pass it to other functions because of the Eta Expansion feature that I mentioned earlier.

Creating `Function` instances manually

As a final way of showing that a function created with `val` creates a complete object, it may help to know that you can create your own `Function1`, `Function2` ... `Function22` instances manually. This gives you another idea of how things work under the hood.

Previously I defined an `add1` function like this:

``val add1 = (a: Int) => a + 1``

Then I showed that it looks like this in the REPL:

``````scala> val add1 = (a: Int) => a + 1
add1: Int => Int = <function1>``````

The following code shows the manual way to create a similar function:

``````class Add2 extends Function1[Int, Int] {
def apply(a: Int) = a + 2
}

Once you’ve taken those steps, you can invoke `add2` just like `add1`:

``add2(1)``

Because `add2` takes an `Int` and returns an `Int`, it’s implemented as an instance of `Function1[Int,Int]`. Had it been a function that took a `Double` and returned a `String`, it would be defined as a `Function1[Double,String]`.

If a function takes two input parameters, you define it as an instance of `Function2`, a function with three input parameters is an instance of `Function3`, etc.

If you copy and paste those `add2` lines of code into the REPL, you’ll see this output, which confirms that it works as described:

``````defined class Add2
res0: Int = 3``````

Using the anonymous class syntax

You can also manually create a function using the anonymous class syntax. Here’s a `Function2` instance named `sumLengths` that adds the lengths of two strings you provide:

``````val sumLengths = new Function2[String, String, Int] {
def apply(a: String, b: String): Int = a.length + b.length
}``````

The REPL shows that it works as expected:

``````scala> sumLengths("talkeetna", "alaska")
res0: Int = 15``````

In practice I don’t create functions like this, but it can be helpful to know some of the things that the Scala compiler does for you.

Using parameterized (generic) types

One thing you can do with `def` methods that you can’t do with `val` functions is use generic types. That is, with `def` you can write a function that takes a generic type `A`, like this:

``def firstChar[A](a: A) = a.toString.charAt(0)``

and then use it as shown in these examples:

``````firstChar("foo")
firstChar(42)``````

You can’t do the same thing with the simple `val` function syntax:

``````// error: this won't compile
val firstChar[A] = (a: A) => a.toString.charAt(0)``````

Coerce a parameterized method into a function

You can coerce a parameterized method into a function. For example, start with a method that uses a generic type:

``def lengthOfThing[A] = (a: A) => a.toString.length``

Then coerce that method into a function as you declare a specific type:

``val f = lengthOfThing[Int]``

Once you do that, you can call the function `f` you just created:

``f(694)``

This works, as shown in the REPL:

``````scala> def lengthOfThing[A] = (a: A) => a.toString.length
lengthOfThing: [A]=> A => Int

scala> val f = lengthOfThing[Int]
f: Int => Int = <function1>

scala> f(694)
res0: Int = 3``````

Kinda-sorta use generic types with `FunctionX` traits

Digging deeper into the magic toolbox ... you can more or less do the same thing by using parameterized types with the `FunctionX` traits, like this `Function2` example:

``````class SumLengths[A, B] extends Function2[A, B, Int] {
def apply(a: A, b: B): Int =
a.toString.length + b.toString.length
}``````

Once you’ve defined that class, you can create a `sumLengths` instance like this:

``````val sumLengths = new SumLengths[Any, Any]

If you paste the class and those last two lines into the REPL, you’ll see this output:

``````defined class SumLengths
sumLengths: SumLengths[Any,Any] = <function2>
res0: Int = 11``````

Some of these examples aren’t very practical; I just want to show some things that can be done.

Summary

In summary, this lesson showed the differences between `val` functions and `def` methods. Some of the topics that were covered are:

• Using `case` expressions with `val` functions and anonymous classes without requiring the leading `match`
• A `def` method is a method in a class (just like a Java method is a method in its class)
• `val` functions are a concrete instances of Function0 through Function22
• `val` functions are objects that have methods like `andThen` and `compose`
• How to manually define `val` functions