# Functions

Let us next discuss how to use functions and collections together to work with data, to illustrate the functional programming style. As a basic example, it is quite concise to write

```
val l = Vector(1.0, 2.3, 3.0)
val sumOfSquares = l.map(v => v*v).sum
```

Indeed, contrast this with the imperative-style equivalent

```
val l = Vector(1.0, 2.3, 3.0)
var i = 0
var sumOfSquares = 0.0
while i < l.length do
sumOfSquares += l(i) * l(i)
i = i + 1
end while
```

The key idea in functional programming is that
we see computation as evaluation (application) of functions on data.
For example, above we first
apply the function `v => v*v`

to each element `v`

of the vector `l`

to get a new vector, namely `Vector(1.0, 5.289999999999999, 9.0)`

.
We then apply the method `sum`

to reduce this vector with
the sum function `(x,y) => x+y`

.

**Higher-order functions.**
Methods and functions that take as arguments or return other functions,
such as the `map`

method of the `Vector`

class used above,
are called higher-order functions.
Also note that, as we only apply functions to data and get new data,
we do not modify the original data: thus we do not use `var`

declarations
or mutable data structures like `ArrayBuffers`

. Rather, we use their
immutable equivalents, such as `Vector`

.

Before we take a closer look on the higher-order functions provided
in the collection classes, let us review how to write *anonymous functions*
such as `v => v*v`

above.

## Anonymous functions

As our running example, consider the code

```
val l = Vector(3, 4, 2, 7, 8, 11)
val evens = l.filter(v => v % 2 == 0)
val sumOfEvens = evens.sum
```

The anonymous function `v => v % 2 == 0`

corresponds to the `val`

defined function

```
val isEven: Int => Boolean = v => (v % 2 == 0)
```

That is: it is a function from integers to Booleans,
returning true on an integer argument `v`

if and only if
`(v % 2 == 0)`

holds (i.e., when `v`

is even).
(To be pedantic, we should actually talk about predicates here as the range of the function is the set of Booleans.)
If we had defined this function explicitly, we could have written

```
val evens = l.filter(isEven)
```

instead of

```
val evens = l.filter(v => v % 2 == 0)
```

**Type inference**.
So how does Scala compiler know that
`v => v % 2 == 0`

is a function from integers to Booleans?

The compiler automatically *infers* this fact from the *context*
where the function is defined and used:
this anonymous function is defined in the parameter list of the `filter`

method of a value of type `Vector[Int]`

. Therefore, the function must
have one argument of the same (or sub-) type as the elements in
the `Vector`

and it must return a `Boolean`

value.

**Underscore notation for anonymous functions**.
Let us also recall the *underscore notation* of anonymous functions.
Namely, we can use the underscore-symbols (“_”)
for denoting the parameters of the function and omit the parameter list.
The first “_” means the first parameter,
the second “_” the second parameter and so on.
For example, the above code can be equivalently written as:

```
val l = Vector(3, 4, 2, 7, 8, 11)
val evens = l.filter(_ % 2 == 0)
val sumOfEvens = evens.sum
```

If some parameter is used more than once in the function body,
then we cannot use the “_” notation.
For instance, “`val squares = l.map(v => v*v)`

” for computing the squares
of values in `l`

cannot be rewritten as “`val squares = l.map(_ * _)`

”:
the “`_ * _`

” defines a function “`(v1,v2) => v1*v2`

” with two parameters,
not the one-parameter function we intended.

Note

**Tech corner: Functions as objects**

How is it possible to pass functions, such as “`v => v % 2 == 0`

” above,
as arguments to other functions?
After all, functions do not only involve data, but also program code!
Well, in fact we can achieve the same thing by using objects only.
As an example, take our anonymous function code “`v => v % 2 == 0`

” above.
Instead of it, we can prepare a separate class

```
class Anonf1 extends Function1[Int,Boolean]:
def apply(v: Int): Boolean = (v % 2 == 0)
end Anonf1
```

that implements the function’s code in the body of the `apply`

method.
Similarly, the command “`val evens = l.filter(v => v % 2 == 0)`

”
is rewritten into:

```
val anonf1 = new Anonf1()
val evens = l.filter(anonf1)
```

The `filter`

-method then calls the `apply`

-method of
the `anonf1`

object when it evaluates the value of the function for
some element `e`

with `anonf1(e)`

(recall that the `apply`

method has a special treatment: we do not have to write `anonf1.apply(e)`

but can use the abbreviated form `anonf1(e)`

).
That is, *instead of program code, we pass objects that implement the code*.

Analogous translations happen automatically in the Scala compiler when it sees our anonymous function definitions.

Let us take a closer look at the
Function1 class for functions with one parameter (similar classes are provided for functions taking no parameters or multiple parameters).
This class provides a `compose`

method defined as:

```
/** Composes two instances of Function1 in a new Function1, with this function applied last.
*
* @tparam A the type to which function `g` can be applied
* @param g a function A => T1
* @return a new function `f` such that `f(x) == apply(g(x))`
*/
@annotation.unspecialized def compose[A](g: A => T1): A => R = { x => apply(g(x)) }
```

This allows us to define functions and then compose them. For instance:

```
scala> val f: Int => Boolean = {v => v % 2 == 0 }
f: Int => Boolean = <function1>
scala> val g: Int => Int = {v => v+1}
g: Int => Int = <function1>
scala> val h = f.compose(g)
h: Int => Boolean = <function1>
scala> h(3)
res: Boolean = true
```

### Anonymous functions with pattern matching

There is also another, very convenient way to define anonymous functions:
pattern matching with case-expressions.
In fact, thanks to Scala 3’s option-less pattern matching, we can often skip the `case`

statement and extract variables from a tuple directly.

For example, we can select the indices at which a list contains an even number as follows:

```
scala> val l = List(1,6,3,7,8,4,5,3)
l: List[Int] = List(1, 6, 3, 7, 8, 4, 5, 3)
scala> val lWithIndices = l.zipWithIndex
lWithIndices: List[(Int, Int)] = List((1,0), (6,1), (3,2), (7,3), (8,4), (4,5), (5,6), (3,7))
scala> val evensWithIndices = lWithIndices.filter((num, _) => num % 2 == 0)
evensWithIndices: List[(Int, Int)] = List((6,1), (8,4), (4,5))
scala> val result = evensWithIndices.map(_._2)
result: List[Int] = List(1, 4, 5)
```

Here the expression `(num, _) => num % 2 == 0`

defines an anonymous
function such that, given a pair as an argument,
it returns true if the first element in the pair is even.
The underscore in `(num, _)`

indicates that the second element in the pair
is not interesting.

Further, the anonymous function `_._2`

(recall that a pair has methods `._1`

and `._2`

returning the first and second element in it, respectively)
in the last `map`

call above could also have been written
as `val result = evensWithIndices.map((_,index) => index)`

.

The `case`

-part of an expression needs to be included if one wants to pattern match nested tuples, however. Further, `case`

-expressions can also have multiple cases,
of which the first matching case is selected,
and inspect the type of the argument object:

```
scala> val l = List("recursion", 2, 2.9)
val l: List[Matchable] = List(recursion, 2, 2.9)
scala> l.foreach({case s:String => {println("a string of length "+s.length)}
case n:Int => println("a number")
case _ => println("an unidentified object") })
a string of length 9
a number
an unidentified object
```

Here we do different things depending of what types we encounter in the list.

We will return to pattern matching and cases in A second implementation with case classes. Alternatively you can study, for example, Section 7 of Scala by Example or Chapter 15 of Programming in Scala, First Edition for more on case classes and pattern matching.

## Methods as functions

In super-precise terms, methods in classes are not functions but methods.
Therefore, we cannot use methods *directly* like functions, for example,
we cannot pass them as parameters to other functions:

```
scala> class A(val x: Int):
def isEven: Boolean = (x%2==0)
override def toString = "x="+x
end A
// defined class A
scala> val l = List(new A(1), new A(3), new A(8))
val l: List[A] = List(x=1, x=3, x=8)
scala> l.filter(A.isEven)
-- [E008] Not Found Error: -----------------------------------------------------
1 |l.filter(A.isEven())
| ^^^^^^^^
| value isEven is not a member of object A
```

To use methods as functions, however, we can define a very simple anonymous function that then calls the method:

```
scala> l.filter(x => x.isEven)
val res: List[A] = List(x=8)
```

Scala offers an easy syntax for treating methods defined in objects as functions: we simply add ” _” after the method name to translate it into a function object:

```
scala> object areaCalculator:
def circle(radius: Double) = scala.math.Pi * radius * radius
def square(side: Double) = side * side
def rectangle(side1: Double, side2: Double) = side1 * side2
def triangle(base: Double, height: Double) = base * height * 0.5
end areaCalculator
// defined object areaCalculator
scala> val circleAreaFunction = areaCalculator.circle _
circleAreaFunction: Double => Double = <function1>
scala> val circleRadiuses = List(2.0, 3.9, 1.2)
radiuses: List[Double] = List(2.0, 3.9, 1.2)
scala> val circleAreas = circleRadiuses.map(circleAreaFunction)
circleAreas: List[Double] = List(12.566370614359172, 47.783624261100755, 4.523893421169302)
```

This ” _”-construction is in fact used automatically by the compiler and thus we can simply write:

```
scala> val circleAreas = circleRadiuses.map(areaCalculator.circle)
circleAreas: List[Double] = List(12.566370614359172, 47.783624261100755, 4.523893421169302)
```

A function obtained in this way can naturally access the elements of its enclosing object. For instance, consider a simple class to help in formatting output:

```
class indentedWriter(s: java.io.PrintStream, prefix: String = ""):
private var level = 0
def println(obj: Any) = s.println(prefix + (" "*level) + obj)
def push : Unit = {level += 2 }
def pop : Unit = {level = 0 max level-2 }
end indentedWriter
```

Now the code

```
val out = new indentedWriter(Console.out, "> ")
val values = Vector(1,2,4)
out.println("The values are:")
out.push
values.foreach(out.println)
out.pop
out.println("Their sum is "+values.sum)
```

outputs

```
> The values are:
> 1
> 2
> 4
> Their sum is 7
```

## Side effects and pure functions

We say that a function or a method has side effects if it, in addition to providing the return value, does at least one of the following

modifies the value of a variable or state of a mutable object that can be accessed outside the function,

causes some other observable interaction with its environment, for instance writes data to the file system, asks for input from the user, and so forth, or

calls some other function that has side effects.

*Remark.* Consumption of computational resources such as time and memory
when executing a function is not considered as a side effect.

As an example, let us consider the following (not so elegant or efficient) function that tests whether a positive integer is a prime number:

```
def isPrimeSlow(n: Int): Boolean =
require(n > 0)
var divisor = 2
while divisor < n do
if n % divisor == 0 then return false
divisor += 1
end while
return true
end isPrimeSlow
```

Even though the function modifies the value of the variable `divisor`

during its execution, the function does not have side effects because
the variable is not visible *outside* the function definition.

### Pure functions

A function is pure if

it does not have side effects, and

its evaluation with the same arguments always gives the same return value.

For instance, our primality checking function above is pure but the function

```
def getDate: String =
val d = new java.util.Date() // get the current date
d.toString
end getDate
```

is not pure even though it does not have side effects.