What Is a Pure Function?
Make a standalone synthetic telemetry calculation predictable.
You will write a telemetry calculation that can be tested, reused, and reasoned about without running a database, clock, network, or dashboard. All readings are synthetic and included in the browser lab: no VPS, account, private repository, or production service is required.
Retrieve before reading
In one sentence: what should determine the result of a function that calculates water usage?
Reveal a strong answer
The result should be determined only by the function's explicit inputs. Nothing else should secretly change it.
The core idea
A pure function has two properties:
- For the same inputs, it returns the same output.
- Calling it has no observable side effect.
That gives us referential transparency: if an expression produces a value, we can replace the expression with that value without changing the program's behavior.
usageFor("M-01", readings) is a good pure-function boundary. The meter id and readings are visible inputs; the result does not depend on the current time, a file, or a hidden dashboard session.
Scala shape
final case class Reading(meterId: String, liters: Double)
def usageFor(meterId: String, readings: List[Reading]): Double =
readings
.filter(_.meterId == meterId)
.map(_.liters)
.sum
The function reads data and returns a number. It does not mutate the list, write a report, or print a message. The same list and meter id always produce the same answer.
Pure core, effect boundary
Functional programs do not avoid all effects. They push effects to an explicit boundary and keep the important reasoning in pure functions.
// Pure core
val liters = usageFor("M-01", readings)
// Effect boundary
println(s"M-01 usage: $liters liters")
The calculation is easy to test. The printing is still useful, but it is visible as an effect at the edge of the program.
This is close to a Rust function over a slice or iterator: explicit arguments in, a value out. Scala's case class is the small data record; map, filter, and sum compose the transformation.
Interactive coding checkpoint
Use the browser lab to change visible inputs, run the calculation, and watch the result change only when the inputs change.
Transform readings into a result
Same inputs. Same result.
Try this sequence:
- Run the function twice without changing anything. The output stays the same.
- Change one explicit input, such as
4.5to8.5, then run again. - Add a reading for a new meter and select it. No hidden server state is involved.
Optional Scala bridge
The browser exercise is the main path. If you later want to compare syntax, the Scala source file contains the same fixture data and assertions. You do not need a CLI to complete this lesson.
Quick check
Which definition is pure?
Spaced review
Before the next lesson, answer these from memory:
- What are the two properties of a pure function?
- Which part of the checkpoint is the effect boundary?
- What hidden input would make a usage calculation impure?
Keep the compact version nearby: Pure functions reference.
Primary source: Chiusano and Bjarnason, Functional Programming in Scala, Chapter 1. For runnable companion material, see the official first-edition exercise repository. This page is an original, self-contained lesson; the book PDF is not required to run the checkpoint.