Reusable Building Blocks
A function (or procedure) packages a piece of logic under a name, so it can be reused wherever needed instead of rewritten. Functions are the primary tool for modularity — building a program from small, well-defined, independently understandable parts. A mathematician's instinct for functions carries over, with a computational twist.
A function has:
- Parameters — named inputs it receives when called.
- A body — the steps it performs.
- A return value — the output it hands back to the caller.
Calling f(3, 4) passes 3 and 4 as arguments to the parameters; the function computes and returns a result. This lets you write the logic once and invoke it many times with different inputs — the DRY principle ("Don't Repeat Yourself").
Scope governs where names are visible. A local variable, defined inside a function, exists only within that function and vanishes when it returns; it cannot be seen from outside. This encapsulation is a feature, not a limitation: a function's internals are hidden, so you can use it knowing only its inputs and output — its interface — without worrying about how it works inside. Two functions can safely use a variable named i without interfering, because each i is local.
Functions enable the whole discipline of abstraction in programming: once written and tested, a function becomes a reliable black box you build upon, just as a proved theorem becomes a tool for further proofs. Well-chosen functions with clear interfaces make programs readable, testable, and maintainable — the difference between a tangle and a structure.
Common pitfall: expecting a local variable to be visible outside the function where it is defined. A local variable exists only within its function's body and is gone once the function returns — this encapsulation is deliberate. Trying to read a function's internal variable from the outside (or assuming two functions' same-named locals are the same variable) misunderstands scope; functions communicate only through their parameters and return value.