Not Every `function` Keyword Writes a Function
Why using the function keyword doesn't make something a function, and the one missing piece that turns a procedure into the real thing.
The last post made the case for writing declarative code that states an outcome instead of narrating steps. Functional programming is how you actually get there, and it all rests on one word: function. I used to think a function was anything written with the function keyword. That belief lasted until I actually tried to write functional code, and realized most of what I called "functions" didn't qualify.
The function keyword is just syntax. It says nothing about what the thing actually does.
A Function That Isn't One
Say you're logging an order summary in an e-commerce checkout:
function logOrderTotal(price, tax, shipping) {
const total = price + tax + shipping;
console.log(`Order total: $${total}`);
}It takes inputs. It does something with them. It even feels useful. But it never hands anything back to whoever called it.
Call logOrderTotal(40, 4, 5) and try to use the result:
const result = logOrderTotal(40, 4, 5);
console.log(result); // undefinedundefined. Every JavaScript function returns something even when you don't write return, but that default return is nothing at all. That's the gap.
The Missing Requirement
A function has to take input and hand back an output. Not print it. Not log it. Return it.
If a block of code has no return keyword, it isn't a function. It's a procedure.
A procedure is any named block of operations. Procedures aren't bad. Every program needs them: things that print to a screen, write to a database, or trigger a side effect. logOrderTotal is a perfectly fine procedure.
It just doesn't get to call itself a function.
function logOrderTotal(price, tax) {
console.log(price + tax);
}Does something with its inputs, but hands nothing back.
function getOrderTotal(price, tax) {
return price + tax;
}Takes inputs, computes a value, and returns it.
It's Contagious
Here's the part that surprised me. Adding a return keyword doesn't automatically make something a function either.
function applyDiscount(price, tax) {
return logOrderTotal(price, tax);
}applyDiscount has a return statement. It looks like a function. But it's returning whatever logOrderTotal gives back, and logOrderTotal always gives back undefined.
A function can only call other functions. Call a procedure, and you become one too.
This isn't a special rule just for this example, it's structural. Whatever a function calls internally decides what it can honestly return, all the way down the call chain. One procedure buried three calls deep taints everything sitting on top of it.
ExpandA Venn diagram showing functions as a smaller circle fully contained inside the larger circle of procedures
Every function is a procedure, since it's still a named block of operations. Not every procedure is a function. That's the actual shape of the relationship, and it's why the function keyword alone never settles the question.
More Than One Output
There's a second wrinkle worth catching early: a function's "one output" can still carry more than one value, as long as it's returned honestly.
function priceRange(base) {
return [base - 5, base + 5];
}
const [min, max] = priceRange(20);
// min = 15, max = 25priceRange technically returns one array. But the moment you destructure it into min and max, you're telling the reader something different: this function actually has two outputs, packaged as one value so it can travel through a single return.
For now, the rule stays simple: no return, no function, no exceptions.
What This Buys You
Later in this series, you'll chain small functions together like pipes: one function's output feeds directly into the next function's input.
const total = addTax(applyDiscount(getPrice(item)));That chain only works if every piece in it actually behaves like a function. Feed applyDiscount a procedure by mistake, and the whole chain silently carries undefined forward, with no error to warn you.
That's the entire payoff of this post. Knowing whether something is a function or a procedure is what tells you whether it's safe to plug into a chain like that one at all.
Having a return is the first requirement, not the last. The next thing to nail down is what that return value is allowed to depend on, and that's where function purity actually starts.
Keep reading