Scala Functions — an intro

Robert Finn
4 min readNov 1, 2021

--

We’ll be covering the following:

  • What is a Function?
  • What are the different Types of Functions?
  • The different syntax possible to define and use Functions

A Simple Function

A function takes an input and returns an output. It is represented by a Trait in Scala ( similar to how an interface with a single method is used to define a Lambda in Java ).

Lets create an anonymous function ( a lightweight function definition used to create an inline Function — think Anonymous class in Java) and assign it to a variable named myFunc

val myFunc: Function1[Int, Int] = new Function1 {
override def apply(v1: Int): Int = {
v1
}
}

Let’s break the expression down:

val myFunc: Function1[Int, Int]

We’re creating an immutable variable called myFunc of type Function1. The first Int within the square brackets specifies that the input will be of type Int and the second Int specifies the output of the Function.

= new Function1 {
override def apply(v1: Int): Int = {
v1
}
}

The definition of the Function — we need to override the apply method and the signature of this method should match the variable type Function1[Int, Int]- e.g. the parameter is of type Int and it returns an Int ( don’t need to specify the return keyword in Scala ).

In this very basic example the Function doesn’t do anything, it just returns the parameter passed to it.

Executing the Function

Now we have our Function defined and stored in our variable myFunc we can pass it around to be used elsewhere ( it is a first class citizen in Scala / it’s just another Object ) or we can call it straight away:

print(myFunc.apply(10))

the .apply() is not required as Scala ( some syntactic sugar that can be applied to Objects ), therefore we can just do the following:

print(myFunc(10))

This will simply print 10 to the console.

Syntactic Sugar

Now we’ve created and executed a Function using the glorious fully verbose format, this is nice initially although having to write Functions in this format every-time would increase the number of lines of code you would need to write.

Syntactic Sugar means we can write the above expression in a different syntactic style although under the hood the compiler will still produce the same code of creating an Object and executing the apply method.

Let’s apply some Syntactic Sugar to the left hand side of the statement first

val myFunc: Function1[Int, Int] = ...

now becomes

val myFunc: Int => Int = ...

The arrow symbol is known as a transformer, it transforms the left hand side into the right, e.g. Int to Int.

Let’s now apply the same syntactic to the right hand side as well:

= (v1: Int) => { v1 }

The full definition therefore becomes:

val myFunc: Int => Int = (v1: Int) => { v1 }

Some final tips:

  • If the function implementation can fit on one line you don’t need the {} brackets
  • Scala can infer the the type of the variable through the right hand side of the expression

This can therefore be simplified further to:

val myFunc = (v1: Int) => v1

Let’s see these all side by side so it’s easy to changes the changes from one to another:

Fully verbose:

val myFunc: Function1[Int, Int] = new Function1 {
override def apply(v1: Int): Int = {
v1
}
}

apply transformer to left and right sides => :

val myFunc: Int => Int = (v1: Int) => { 
v1
}

final pieces:

val myFunc = (v1: Int) => v1

and you can easily see how if you have many functions the two final versions are preferable.

Sweet we’ve got the syntax out of the way…

( sorry.. )

Let’s look at the different built in Function Types:

  • Function1
  • Function2
  • Function3
  • etc… up to Function 20 something

The only difference here is the number of inputs to the Function.

Let’s explore some silly examples

Function2

// The final generic type in the square brackets will always be
// the return type
val addTwo: Function2[Int, Int, Int] = new Function2 {

// method signature much match above
override def apply(v1: Int, v2: Int) {
v1 + v2
}
}

Similarly a Function3 ( we’ll go for the shorthand version here ):

val addThree = (v1: Int, v2: Int, v3: Int) => v1 + v2 + v3

Note: when using syntactic sugar to define your function type you have to use brackets when there is more than one input parameter on the left hand side of the transformer.

val addThree: (Int, Int, Int) => Int = ...

Final thoughts

Now you should be all set to start creating your own Functions in Scala, in future I’m planning to dive into some further concepts such as Higher Ordered Functions.

--

--