Functions and Methods

As with other programming languages, a Scala function lets you create a reusable block of code. This is a set of instructions that performs a specific task, and like other languages, a function should do only one thing, like read a file, write to a web service, calculate tax on an order, etc.

A function typically takes one or more input parameters, runs its algorithm, and then has a return value. For example, this is a function that doubles the integer it’s given:

def double(i: Int): Int = i * 2

When you first start working with Scala, it may be easier to read the function when the function body is on a separate line, like this:

def double(i: Int): Int =
    i * 2

Return vs yield or evaluate

In Scala we don’t say that a function returns a result as much as it yields a result or evaluates to a result, and I’ll talk about this as we go through these function lessons.

Function vs method

Scala 3 blurs the lines between a function and a method, so I use this terminology:

  • If it’s inside a class or trait, I call it a method
  • Otherwise, I call it a function

Functions and methods can be defined in these locations:

  • In a class, trait, or object
  • In Scala 3, functions don’t have to be in those containers; they can be outside of those containers, and we call these toplevel functions

Other features of functions

  • Parameters can have default values
  • Advanced: a feature known as “givens”
  • Advanced: a function can have multiple input parameter groups

General syntax

A basic function looks like this:

def functionName(param1: Type1, param2: Type2): ReturnType =
    // the
    // function
    // body

Functions can get more complicated when we use:

  • Generic parameters
  • Default parameter values
  • An advanced feature known as “givens”

You’ll see those features in future lessons.

First examples (one-liners)

These are some functions that I define on one line:

// define them
def add(i: Int, j: Int): Int = i + j
def multiply(i: Int, j: Int): Int = i * j

// use them
val a = add(1, 1)
val b = multiply(1, 1)

Here’s an example of a function body that is more than one line long:

// note: last line is the value the function yields
def add(i: Int, j: Int): Int =
    // comment
    i + j

Notice that you just indent the body of the function.

More of a real-world, multiline example:

// [1] this works, and uses one variable at a time
def multilineStringToList(s: String): Seq[String] =
    val linesArray: Array[String] = s.split("\n")
    val linesSeq = linesArray.toSeq
    val linesTrimmed = linesSeq.map(_.trim)
    linesTrimmed.filter(_ != "")

// [2] this is the same algorithm
def multilineStringToList(s: String): Seq[String] =
    s.split("\n")
     .toSeq
     .map(_.trim)
     .filter(_ != "")

// [3] this is how you use either of those functions
val ms = """
one
two
three
"""

multilineStringToList(ms)

The function return type

Specifying the function return type is optional, but I almost always declare it. One place you might not declare it is in small scripts.

def add(i: Int, j: Int): Int = i + j    // with the return type

def add(i: Int, j: Int) = i + j         // without the return type

A function can return whatever you need, such as a tuple:

def strlen(s: String): (String, Int) =
    (s, s.length)

or a list of tuples:

def strlens(xs: Seq[String]): Seq[(String, Int)] =
    xs.map(s => (s, s.length))

val names = List("joey", "pacey", "dawson")

val namesAndLengths = strlens(names)    // Seq[(String, Int)]
namesAndLengths.foreach( t => println(s"${t(0)}, ${t(1)}"))
namesAndLengths.foreach( t => println(s"${t._1}, ${t._2}"))

Or anything else you need!