Based on the code snippets developed in class, summaries and explanations in this document were drafted with the assistance of generative AI. The author verified all facts, revised the text for coherence, and takes full responsibility for the final content.
Week 3 Overview
Week 3 covers statements and expressions, strict and non-strict evaluation, and functions on lists. The snippets move from methods to function values, then to higher-order functions, and close with the evaluation strategy of function arguments: call-by-value versus call-by-name. Currying and folds follow in week 4.
1. From Methods to Functions
A good starting point is to compare a method definition in an object with a function value.
object Methods:
val x = 5
def add(y: Int, z: Int) = x + y + z
end MethodsThe method add is part of object structure and can use object fields (x). Now compare that with a function value:
val add: (Int, Int) => Int =
(x: Int, y: Int) => x + y
val add2: (Int, Int) => Int =
(_: Int) + (_: Int)The difference matters for the rest of the course: methods organize behavior in class/object structure, while functions are first-class values that can be passed, returned, and stored.
Scala 3 Book pointers: - Methods: https://docs.scala-lang.org/scala3/book/methods-main-methods.html - Functions: https://docs.scala-lang.org/scala3/book/fun-intro.html - Anonymous functions: https://docs.scala-lang.org/scala3/book/fun-anonymous-functions.html
Practical relevance: In larger systems, methods are useful for stable APIs, while function values make extension points easy (custom sorting, callbacks, validation pipelines, strategy selection).
2. Higher-Order Functions: Passing Behavior
Once functions are values, we can pass behavior into generic code:
def g(x: Int, y: Int, f: (Int, Int) => Int) =
f(x, y)
end g
g(1, 2, _ + _)
g(1, 2, (x, y) => x + y)We can also return functions from functions:
def createAdd(): (Int, Int) => Int =
val result: (Int, Int) => Int =
(x: Int, y: Int) => x + y
result
end createAdd
val sum: Int = createAdd()(3, 4)This is the core idea of higher-order programming from the functions-on-lists lecture: separate traversal or orchestration logic from the specific operation.
Scala 3 Book pointers: - Higher-order functions: https://docs.scala-lang.org/scala3/book/fun-hofs.html
Practical relevance: This style scales well in production code because shared infrastructure can remain unchanged while business rules are injected as function arguments.
3. Call-by-Value and Call-by-Name
The strict/non-strict lecture ends on how a function argument is evaluated. With call-by-value, the argument is evaluated once before entering the function.
def f(x: Double) : Double =
val x1 = x
val x2 = x
x1 - x2
end f
f(Math.random())With call-by-name (=>), each use can re-evaluate the argument expression.
def g(x: => Double) : Double =
val x1 = x
val x2 = x
x1 - x2
end g
g(Math.random())Because Math.random() may run twice in g, the result is not guaranteed to be 0. A call-by-name parameter is a thunk: the argument travels unevaluated and is evaluated at each use, which is what makes user-defined non-strict constructs possible. We pick this up again in week 6, where argument passing is compared across languages.
Scala 3 Book pointers: - Control structures and function arguments: https://docs.scala-lang.org/scala3/book/control-structures.html
Practical relevance: By-name arguments let a library defer or skip expensive work — logging that formats its message only when the level is enabled, assertions, and custom control constructs.
Summary
Week 3 connects three core ideas:
- Functions are values, so behavior can be passed and returned.
- Higher-order functions separate traversal from the operation applied to each element.
- The evaluation strategy of an argument decides when, and how often, its expression runs.
This progression is central to building scalable functional components: concise APIs, reusable behavior, and predictable evaluation.