awesome-everything RU
↑ Back to the climb

Base CS from zero

Parameters and return values

Crux Parameters are values copied into the new frame before the function body runs. The return value is handed back to the caller when RET fires. Both pass data through the stack frame boundary.
◷ 20 min

You can now trace the call stack as functions are called and returned. The next question is: how does data get into a function, and how does the result get back out?

A function that always works on the same fixed values is almost useless. Real functions take parameters — values provided by the caller at call time — and produce a return value that the caller can use. These two mechanisms are the interface between a function and the code that calls it, and they both operate through the stack frame.

Goal

After this lesson you can explain what a parameter is (a value copied into the new frame at call time), what a return value is (a value produced by the function and handed back to the caller), and trace a function call that takes parameters and returns a value, showing the frame contents at each step.

The idea

Parameters are declared in the function signature. When the caller issues the CALL, the values it supplies (called arguments) are copied into the new frame before the function body starts executing. Inside the function, parameters look and behave exactly like local variables — they are named cells inside the frame. The difference is that they are pre-populated with the caller’s values rather than being set by assignment.

In TypeScript syntax, function add(x: number, y: number): number declares two parameters x and y. At the call site add(3, 5), the values 3 and 5 are the arguments that get copied into the new frame’s x and y cells.

Return values work in the reverse direction. When the function body reaches a return statement, it computes the value to return and makes it available to the caller. In hardware, this is typically done by placing the return value in a CPU register (a fast storage slot inside the CPU itself) before firing RET. The caller can then read that register after RET restores the program counter.

The key insight: parameters pass data into a frame; the return value passes data out. Both crossings happen at the frame boundary — the moment of CALL (in) and RET (out).

The function to trace: add(x, y) takes two numbers and returns their sum. The trace shows add(3, 5), with the stack before the call, during execution, and after the return.

The code
1 function add(x: number, y: number): number {
2 let result = x + y; // result is a local variable in add's frame
3 return result; // hands result back to the caller
4 }
5
6 function main(): void {
7 let total = add(3, 5); // caller: arguments 3 and 5 passed to add
8 // total now holds 8
9 }
  • L1 x and y are parameters — they live in add's frame, pre-filled with the caller's arguments
  • L2 result is a local variable — add's frame now holds x, y, and result
  • L3 return: places the value of result in a register, then RET fires
  • L7 add(3,5): arguments 3 and 5 are copied into add's new frame as x and y
  • L8 after RET: the register holding 8 is read; total is assigned 8 in main's frame
add(3, 5): parameters enter add's frame at call; return value leaves via a register at RET.
Step-by-step trace

Trace main() which calls add(3, 5). Each cell shows one frame’s contents.

1 function add(x: number, y: number): number {
2 let result = x + y;
3 return result;
4 }
5
6 function main(): void {
7 let total = add(3, 5);
8 }

Why this works

Why are parameters copied into the frame rather than shared with the caller? Because each function call needs an independent workspace. If add could modify the caller’s 3 and 5, calling add twice with different arguments would be impossible to reason about. Copying the values means the callee’s frame is entirely self-contained — the callee can freely modify its x and y cells without changing anything in the caller’s frame. This “copy-in” behaviour is called pass-by-value and it is the default in most languages for primitive values like numbers.

Practice 0 / 5

function multiply(a: number, b: number): number { return a * b; } — How many parameters does multiply have?

multiply(4, 6) is called. What value does multiply return?

After multiply(4, 6) returns, how many stack frames are on the stack (assuming it was called from main and nothing else is active)?

function square(n: number): number { return n * n; } — square(7) is called. What value is placed in the return register?

function add(x: number, y: number): number { let r = x + y; return r; } — add's frame holds x, y, and r. How many named cells does add's frame contain?

Check yourself
Quiz

When add(3, 5) is called, where do the values 3 and 5 live during add's execution?

Recap

Parameters are named cells in a function’s stack frame, pre-filled with the arguments (values) the caller supplied at call time. Inside the function, parameters behave exactly like local variables. The values are copied into the frame (pass-by- value for primitives), so the callee has an independent workspace. A return value is produced by the return statement: the value is placed in a CPU register, RET fires, the frame is popped, and the caller reads the return value from the register. Parameters carry data into the frame at CALL; the return value carries data out of the frame at RET.

Continue the climb ↑Scope
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.