A return statement doesn’t necessarily return to the call site that called the current method, but it can return at once from the callee, its caller, the caller’s caller, and so on.


A return statement can unwind multiple call stack frames


A return statement pops exactly one call stack frame

Here is what's right.

A return statement always returns to the call site that called the current method. It always unwinds only one call stack frame. It only finishes the current method activation, continuing execution right after the call site who is responsible for the current activation.

So, in a sequence diagram, this means a return arrow points to the same lifeline from which the corresponding call arrow came. It can’t point to a different lifeline.


The call of Pedal.push() (1) is paired with return arrow (4), and the call of Engine.accelerate() (2) is paired with return arrow (3).

How do you know your students might have this misconception?

A good way to detect this misconception is through the use of (UML-like) sequence diagrams. If the call and return arrows don’t match up, students might have this misconception. Here is an example incorrect sequence diagram:


While there are two nested calls (1 and 2), students may only draw a single return arrow (3) that unwinds both stack frames.

While this misconception applies to returns in general, it is particularly prevalent in returns from recursive calls. Students sometimes assume that all calls in a recursion can be completed at once by a single return statement. That is, they assume a return statement unwinds the call stack similar to the way an expression does.

How can you build on this misconception?

Exception handling

If students assume that return unwinds multiple stack frames, then they may be happy to learn that raise indeed may do so. Thus, when clarifying this misconception, one can explain that in exception handling indeed multiple stack frames can be unwound due to one single (raise) statement.

Continuation-Passing Style, Asynchronous Calls, Multithreading

The following ideas are somewhat less directly related to this misconception, but students may encounter them in more advanced courses. There are various reasons why one might draw variants of sequence diagrams where activations are not properly nested and properly delineated by call arrows and return arrows.

For example, in continuation-passing style (CPS), methods never get to return. A method always calls another method after it completes its own work. The last method to be called then kills the entire program. Thus no return ever happens. This means that there won’t be any return arrows at all. (However, if the last method did not kill the program, then at that point the methods that had been called would return one by one.)

Another example where sequence diagrams somewhat deviate from the simple model are asynchronous calls (calls to asynchronous APIs), where a call does return, immediately, just to the caller, but the work on the callee may continue.

In general, in multi-threaded programs, there will be multiple stacks, each with its own proper nesting of calls and returns. However, a sequence diagram may include special arrows to denote communication between threads. And that might include arrows that are not paired with “return arrows”.

Stay up-to-date

Follow us on  twitter to hear about new misconceptions.