Scala Functions: def, Lambda, and Higher-Order Functions
Functions are first-class citizens in Scala — they can be passed as arguments, returned from other functions, stored in variables, and composed together. This makes Scala's functional programming capabilities qualitatively different from Java, where lambdas are a bolted-on addition. Understanding how Scala handles functions is fundamental to writing idiomatic code.
Defining Functions with def
The basic function definition:
def greet(name: String): String =
s"Hello, $name!"
greet("Alice") // "Hello, Alice!"Multi-line functions use a block expression:
def max(a: Int, b: Int): Int =
if a > b then a else bThe last expression in a function body is its return value — no return keyword needed (though it exists for early returns).
Functions with default parameters:
def connect(host: String, port: Int = 8080): String =
s"Connecting to $host:$port"
connect("localhost") // "Connecting to localhost:8080"
connect("example.com", 443) // "Connecting to example.com:443"Named arguments:
connect(port = 9000, host = "db.server")Anonymous Functions (Lambdas)
Anonymous functions are function literals — functions without a name:
val double = (x: Int) => x * 2
double(5) // 10
val add = (a: Int, b: Int) => a + b
add(3, 4) // 7When the type can be inferred from context, you can omit it:
val numbers = List(1, 2, 3, 4, 5)
numbers.map(x => x * 2) // List(2, 4, 6, 8, 10)Placeholder syntax — _ as shorthand for a single parameter used once:
numbers.map(_ * 2) // same as x => x * 2
numbers.filter(_ > 3) // same as x => x > 3
numbers.reduce(_ + _) // same as (a, b) => a + bHigher-Order Functions
A higher-order function takes another function as a parameter or returns a function:
def applyTwice(f: Int => Int, x: Int): Int =
f(f(x))
applyTwice(_ * 2, 3) // 12 (3 * 2 = 6, 6 * 2 = 12)
applyTwice(_ + 10, 5) // 25The type Int => Int represents a function from Int to Int. For two parameters: (Int, Int) => Int.
Returning a function:
def multiplier(factor: Int): Int => Int =
(x: Int) => x * factor
val triple = multiplier(3)
triple(7) // 21
val times10 = multiplier(10)
times10(4) // 40Function Values vs Methods
There is a subtle distinction between def methods and function values:
def add(a: Int, b: Int): Int = a + b // method — belongs to a class
val addFn: (Int, Int) => Int = add // function value — eta-expansionWhen you use a def where a function value is expected, Scala automatically performs eta-expansion — converting the method to a function value.
Currying
Currying transforms a function with multiple parameters into a chain of single-parameter functions:
def add(a: Int)(b: Int): Int = a + b
val add5 = add(5) // partially applied — returns Int => Int
add5(3) // 8
add5(10) // 15Multiple parameter lists in Scala enable currying. The add(5) call returns a new function that adds 5 to its argument.
Practical use — custom control structures:
def repeat(n: Int)(block: => Unit): Unit =
var i = 0
while i < n do
block
i += 1
repeat(3):
println("Hello!")
// Hello!
// Hello!
// Hello!Partial Application
Partial application fixes some arguments of a function, producing a new function:
def power(base: Int, exp: Int): Int =
Math.pow(base, exp).toInt
val square = power(_, 2) // fix exp=2, base is free
val cube = power(_, 3)
square(5) // 25
cube(4) // 64The _ placeholder marks the free (unfixed) argument.
Frequently Asked Questions
Q: What is the difference between => and -> in Scala?
=> is the function arrow — used in function types (Int => String) and lambda bodies (x => x * 2). -> creates a tuple pair, commonly used in Map literals: Map("key" -> "value"). They are unrelated operators. -> desugars to ("key", "value").
Q: When should I use def vs val for a function?
Use def for methods on classes and for functions that should be computed each time they are called (or that have side effects). Use val for function values you want to store, pass around, or partially apply. In practice, def is the default choice and val for a function is used when you are explicitly treating the function as a value.
Q: What is the => in a parameter type like block: => Unit?
=> Unit (with no left side) is a by-name parameter — the argument is not evaluated when passed, but each time it is used in the function body. This is how Scala implements custom control structures: passing a block of code that executes later. It is different from () => Unit (a zero-argument function that must be explicitly called with ()).
Part of the Scala Mastery Course — Module 5 of 22.
