Functions

A function is basically a method, but we can use a function as a first-class value:

Here's an example where we give the name add42 to a function that adds 42 to its input.

val add42 = (x: Int) => x + 42
// add42: Function1[Int, Int] = repl.MdocSession$MdocApp$$Lambda$13883/0x0000000103a92040@35b5b6a1

We can call it just like we'd call a method.

add42(0)
// res0: Int = 42

This is an example of a function literal. Let's learn about them now.

Function Literals

We've just seen an example of a function literal, which was

(x: Int) => x + 42
// res1: Function1[Int, Int] = repl.MdocSession$MdocApp$$Lambda$13884/0x0000000103a76040@2e921698

The general syntax is an extension of this.

<div class="callout callout-info">

Function Literal Syntax {-}

The syntax for declaring a function literal is

(parameter: type, ...) => expression

where - the optional parameters are the names given to the function parameters; - the types are the types of the function parameters; and - the expression determines the result of the function.

The parentheses around the parameters are optional if the function has just a single parameter. </div>

Function Types

To pass functions to methods we need to know how to write down their types (because when we declare a parameter we have to declare its type).

We write a function type like (A, B) => C where A and B are the types of the parameters and C is the result type. The same pattern generalises from functions of no arguments to an arbitrary number of arguments.

Here's an example. We create a method that accepts a function, and that function is from Int to Int. We write this type as Int => Int or (Int) => Int.

def squareF(x: Int, f: Int => Int): Int =
  f(x) * f(x)

We can pass add42 to this method

squareF(0, add42)
// res2: Int = 1764

We could also pass a function literal

squareF(0, x => x + 42)
// res3: Int = 1764

Note that we didn't have to put the parameter type on the function literal in this case because Scala has enough information to infer the type.

<div class="callout callout-info">

Function Type Declaration Syntax {-}

To declare a function type, write

(A, B, ...) => C

where

If a function only has one parameter the parentheses may be dropped:

A => B

</div>

Functions as Objects

All first class values are objects in Scala, including functions. This means functions can have methods, including some useful means for composition.

val addTen = (a: Int) => a + 10
// addTen: Function1[Int, Int] = repl.MdocSession$MdocApp$$Lambda$13886/0x0000000103a90840@1b29e778
val double = (a: Int) => a * 2
// double: Function1[Int, Int] = repl.MdocSession$MdocApp$$Lambda$13887/0x0000000103a88040@72e8ce3
val combined = addTen.andThen(double) // this composes the two functions
// combined: Function1[Int, Int] = scala.Function1$$Lambda$13817/0x0000000103a70040@1f362219 // this composes the two functions
combined(5)
// res4: Int = 30

Calling a function is actually calling the method called apply on the function. Scala allows a shortcut for any object that has a method called apply, where can drop the method name apply and write the call like a function call. This means the following are equivalent.

val halve = (a: Int) => a / 2
// halve: Function1[Int, Int] = repl.MdocSession$MdocApp$$Lambda$13888/0x0000000103a8f040@21aec1b1
halve(4)
// res5: Int = 2
halve.apply(4)
// res6: Int = 2

Converting Methods to Functions

Methods are very similar to functions, so Scala provides a way to convert functions to methods. If we follow a method name with a _ it will be converted to a function.

def times42(x: Int): Int =
  x * 42

val times42Function = times42 _
// times42Function: Function1[Int, Int] = repl.MdocSession$MdocApp$$Lambda$13889/0x0000000103a9f040@7568f0db

We can also write a method call but replace all parameters with _ and Scala will convert the method to a function.

val times42Function2 = times42(_)
// times42Function2: Function1[Int, Int] = repl.MdocSession$MdocApp$$Lambda$13890/0x0000000103a9e840@6d23301

Exercises {-}

Function Literals

Let's get some practice writing function literals. Write a function literal that:

<div class="solution"> The first function is

(x: Int) => x * x
// res7: Function1[Int, Int] = repl.MdocSession$MdocApp$$Lambda$13891/0x0000000103a9d840@28daff28

The second is

(c: Color) => c.spin(15.degrees)
// res8: Function1[Color, HSLA] = repl.MdocSession$MdocApp$$Lambda$13892/0x0000000103a8e840@7f2e10cb

The third is

(image: Image) => 
  image.beside(image.rotate(90.degrees))
    .beside(image.rotate(180.degrees))
    .beside(image.rotate(270.degrees))
    .beside(image.rotate(360.degrees))
// res9: Function1[Image, Image] = repl.MdocSession$MdocApp$$Lambda$13893/0x0000000103a8d840@4d72d9dd

</div>

Function Types {-}

Here's an interesting function we'll do more with in later sections. We don't need to understand what it does right now, though you might want to experiment with it.

val roseFn = (angle: Angle) =>
  Point.cartesian((angle * 7).cos * angle.cos, (angle * 7).cos * angle.sin)

What is the type of the function roseFn defined above? What does this type mean?

<div class="solution"> The type is Angle => Point. This means roseFn is a function that takes a single argument of type Angle and returns a value of type Point. In other words, roseFn transforms an Angle to a Point. </div>

Paths→