Understanding Function Calls and Returns
Code file order (top to bottom) is not the same as execution order (the actual sequence the program runs).
The Reading Trap
A program is often displayed as a file that can be read from top to bottom. However, the order in which the lines appear in the file is not necessarily the order in which the program runs. When execution reaches a function call, the next part of the program to follow is the called function and its body, not simply the next line in the file.
Separate two ideas: file order describes where code is written, while execution order describes the actual sequence the program follows.
Following the Transfer
A useful execution-flow habit is to treat a function call as a transfer of attention. Begin at the calling line. When that line calls a function, move to the function body and trace the path taken there. The function body is the next part of the program that matters for understanding what happens. After the function finishes, continue tracing from the caller at the point where the call occurred.
A Complete Execution Trace
Consider this generated, language-neutral example. A program has a first step, a call to a function named prepare, a later step, and a function body containing two steps. The file may show the later step before the function body because the function is written elsewhere in the file. A linear reader might move directly to that later step. An execution-flow reader instead follows the call into prepare first.
Tracing the prepare call
Determine the execution sequence for a program whose caller reaches a call to prepare, whose prepare function contains two steps, and whose caller has one step after the call.
1. Start with the caller: Begin at the first step of the program and move through the caller until execution reaches the call to prepare.
2. Follow the call: At the call, move into the body of prepare rather than continuing immediately to the later caller step.
3. Trace the function body: Follow the two steps inside prepare in their execution path.
4. Return to the caller: When prepare finishes, resume the caller at the point after the call.
5. Continue the caller: Follow the caller's later step.
The execution path is: first caller step, call to prepare, first prepare step, second prepare step, return to the caller, later caller step.
Tracing Beyond Functions
Execution-flow reading is broader than tracking a single function call. A complete trace follows the actual path through function calls, conditionals, and loops. This means the reader asks which path the program takes next instead of assuming that every line in the file will be followed in simple top-to-bottom order.
When tracing, write down the next execution step after every transfer. Record the caller, the function entered, the path inside the function, and the point where execution continues afterward. This keeps file layout from being confused with runtime behavior.
Replacing Linear Reading
Linear reading is still useful for locating code, but it is not always the best way to understand behavior. Once you find the starting point, switch to execution-flow reading: follow the current path, enter functions when they are called, account for conditionals and loops, and resume at the caller after a function finishes. This approach is often more sensible and effective because it follows the program's actual path.
Assuming the next line in the file is always the next line that runs.
A function call changes the execution path by directing the trace into the called function.
Fix:
Follow the call into the function body before continuing with the caller.Stopping the trace at the function call.
The function body is part of the actual path the program takes.
Fix:
Trace the function body and then resume the caller after the function finishes.Treating every visible line as part of one uninterrupted path.
Execution flow can include function calls, conditionals, and loops that determine the path taken.
Fix:
Ask what execution reaches next and trace the selected path.
Practice the Trace
Imagine a program whose caller reaches a function named check. The function body contains one step, and the caller contains another step after the call. Describe the execution sequence in order. Then explain why reading only from the top of the file could produce a different interpretation.
Hints
- Begin at the caller and stop when you reach the call to check.
- Follow the function body before moving to the caller's later step.
- End by stating where execution continues after the function finishes.
What do you think happens?
A trace reaches a function call. What should you inspect next if your goal is to follow execution rather than file order?
Reveal answer
Answer: The body of the called function
Following execution flow means tracing the function call into the called function, then continuing from the caller after that function finishes.
Key Takeaways
- File order and execution order are different ways of viewing a program.
- When execution reaches a function call, trace the called function as part of the actual path.
- After a function finishes, continue tracing from the caller's continuation point.
- Execution-flow reading can include function calls, conditionals, and loops.
- Following execution flow is often more effective for debugging and predicting behavior than reading only from top to bottom.