Base CS from zero
Functions and the call stack: build a stack tracer
Reading a stack trace in a lesson is not the same as building one yourself. In this project you make the call stack visible: instrument a small recursive program so it prints the stack as it pushes and pops, then deliberately drive it into a stack overflow and explain exactly what ran out.
Turn the unit’s mental model into something you can run: a program that shows its own frames being pushed and popped, demonstrates that parameters are copied, and reproduces a real stack overflow with a measured depth.
Build a small program (TypeScript/JavaScript, or any language you prefer) that makes its own call stack observable for a recursive function, then use it to demonstrate pass-by-value, scope/lifetime, and a real stack overflow — proving each claim by running the program, not by describing it.
- Running the instrumented program prints the frames pushing on the way down and popping on the way up, with the indentation/depth matching the expected peak (n + 1 or n + 2).
- The maintained depth counter is shown returning to 0 after completion, evidencing one pop per push.
- The pass-by-value demo shows the caller's number unchanged after the callee reassigned its parameter, with the object-mutation contrast explained correctly.
- The program produces a genuine stack-overflow error (captured output or screenshot) and you report the approximate max depth, with a one-paragraph explanation naming the fixed stack region as the resource that was exhausted and the missing base case as the cause.
- Render the stack as a live visual: print or draw the stack of frames at each step (oldest at the bottom), so the trace looks like the AlgoTrace from the lesson.
- Convert the recursive version into an equivalent iterative loop and compare peak memory behaviour — show that the loop uses one frame regardless of n while the recursion's depth scales with n.
- Measure the actual maximum recursion depth your runtime allows before overflow, and estimate the per-frame size from that depth and a known stack-region size (e.g. 1-8 MB); discuss why bigger frames mean shallower allowed recursion.
- Add a second recursive function with two self-calls per level (e.g. a naive Fibonacci) and show how the stack depth still scales with the longest single path, not the total number of calls.
This is the loop behind every debugger stack trace you will ever read: a call pushes a frame, a return pops it, parameters are copied in, locals live and die with the frame, and recursion is the same push repeated until a base case stops it — or until the fixed stack region overflows. Building the tracer once, and crashing it on purpose, turns the unit’s diagram into something you have actually watched happen.