Outcome: connect runtime values to checked types and place one repeated calculation behind a named function.
Prerequisite: complete First Program and be able to run topaz check before topaz run.
Extend the working file
Create values-functions.tpz:
function minutesLeft(total: int, spent: int) -> int {
total - spent
}
let topic = "Topaz basics"
let total: int = 45
let spent = 20
let mut sessions = 0
sessions = sessions + 1
print("{topic}: {minutesLeft(total, spent)} minutes left")
print("sessions: {sessions}")Check and run the continuation:
topaz check values-functions.tpz
topaz run values-functions.tpz
The observed result is:
Topaz basics: 25 minutes left
sessions: 1Read from the result back to the code
The first line contains the result of minutesLeft(45, 20). Its signature names two int parameters and promises an int result. The last expression, total - spent, becomes that result without a written return. Use return when an early exit makes the control flow clearer; the declared result type still applies to every exit.
topic and spent need no annotations because their initial values make the types clear. total: int writes the boundary explicitly. All three names are immutable: the program can use their values but cannot replace them.
sessions is different. let mut states that reassignment is intentional, and the next line changes its value from 0 to 1. Mutation belongs on the binding that tracks changing state, not on every value merely because it might change someday.
Decision: infer, annotate, or mutate?
Prefer ordinary let with inference for a local value whose type is obvious. Add an annotation when it communicates an important boundary. Add mut only when later reassignment is part of the model. A function signature should be explicit because callers rely on its parameter and result contract.
Try this
Change total to 60 and spent to 15. Leave sessions unchanged. What changes in the output?
Answer
The first line becomes Topaz basics: 45 minutes left; the second remains sessions: 1. The function receives the new arguments, while the separate mutable counter still increments once.
Ready to continue when
You can explain an inferred type, a written annotation, an immutable binding, a mutable binding, two parameters, and the expression that supplies the function result.
For exact forms, see Types and Functions & Generics. Generics are later reference material, not a prerequisite. Continue to Data and Control.