10. Understanding How Methods Work

Key concepts

  1. Mental models: Substitution and Control Flow
  2. Drawing Pictures of Method Invocations
In this lesson, we'll look at a couple of mental models that are helpful in understanding the mechanics of a method call: substitution and control flow. Throughout this section, we'll use the terms message send, method call, or method invocation equivalently.

Substitution

In this model, we can imagine that the call to the method is literally replaced with the code of its body, substituting arguments for parameters. Recall the method definition for deposit:

void deposit(double amount) {

  this.balance = this.balance + amount;

}

The following message send:

account.deposit(35.0);

could be rewritten as:

account.balance = account.balance + 35.0;

The rule for rewriting is to first replace the message send with the body of the method definition, replacing the parameter names (amount, in this case) with the corresponding values of the arguments (35.0, in this case). Also, the name this is everywhere replaced by the name of the object that is receiving the message (account, in this case).

Control Flow

We will often talk about the flow of control in a program. This is really just a way of thinking about the sequence of statements being executed. Remember that the machine only executes one statement at a time. In a simple piece of code, we simply execute one statement after another:

int x = 10;

int y = x * x;

String myName = "Bill";

However, in a segment of code containing message sends, there is more going on than meets the eye.

double amount = 15.25;                               // line 1

account.deposit(amount);                             // line 2

double euros = account.convertBalance(1.10);         // line 3

The first line executes by binding the name amount to the value 15.25. The second line calls a method that returns no value. The next statement that executes is actually inside of the method deposit. When this statement completes, control passes back to this fragment and the third line is executed. This line binds the name euros to the value returned by the convertBalance method. To calculate that value, control must pass to the body of that method.

Thinking about method calls in terms of change of control flow is closer to the way method calls actually take place. More formally, when a method is called, the arguments to the method are first evaluated. Next, the names of the method's parameters are bound to the values of its arguments. Finally, control is passed to the first line of the method, and execution continues inside of the body of the method until either a return is encountered, or there are no more statements to execute. At this point, control passes back to the call site -- the point where the method was originally called.

Drawing Pictures

Just as it's been helpful to draw pictures of objects, and the names that refer to them, we can draw pictures to help understand method invocation. Let's use the below class definition as our example:

public class BankAccount {

  private int number;

  private double balance;

  private String name;



  public void deposit(double amount) {

    this.balance = this.balance + amount;

  }



  public void withdraw(double amount) {

    this.balance = this.balance - amount;

  }



  public void transferFrom(BankAccount other, double amount) {

    other.withdraw(amount);

    this.deposit(amount);

  }



  // And some other methods...



}

And now, let's draw pictures for what happens when the following fragment executes:

BankAccount account1 = new BankAccount(1234, 225.34, "Bill");

BankAccount account2 = new BankAccount(23455, 125.0, "George");

account1.transferFrom(account2, 75.0);

The basic idea is to imagine that the machine has a bunch of pieces of scratch paper. When it needs to execute a sequence of statements such as the above, it gets a new sheet of paper, and starts drawing. After the first line in the above fragment is executed, the following drawing results:

The box on the left is not an object, rather it is the way we draw a sheet of scratch paper. We've titled the piece of paper to differentiate it from other sheets of paper we'll be adding to this picture later on. In this case, we've chosen the arbitrary name "fragment" for our sheet of scratch paper. We modify the picture after executing the second line:

Now, things get interesting. When a message send takes place, we get a new piece of scratch paper, title it with the name of the message, and start drawing on that sheet of paper. Remember, when a method is invoked, parameter names are bound to the corresponding argument values, so we need to show those names on our paper. When control passes to the transferFrom method, the following picture results:

Notice that we've written three names: this (referring to the first bank account), other (referring to the second bank account), and amount (referring to the value 75.0). We show the binding for this to denote the object that is receiving the message.

Remember that the first thing that the transferFrom method does is call another method, withdraw. Again, this means adding another piece of scratch paper to our picture. When control passes to the withdraw method, the following picture describes the state of the world:

It's starting to look a bit messy, but we've really just added another piece of paper, and a couple of names to our world. Notice that on this new piece of paper, the name this refers to a different object than the name this on the piece of paper for tranferFrom. That makes sense, because each of those message sends have different receivers. Writing down which object this refers to helps us keep straight which object is handling a given message.

Now imagine that the withdraw method finishes. What's next? Well, control returns to the call site -- in the body of the transferFrom method. At this point, the piece of paper for withdraw is thrown away, and the following picture results. You've seen it before, except that the second bank account is missing some money -- due to the impact of the withdrawal we just made.

The next line of the body of transferFrom sends the deposit message to this. Again, we modify our picture to reflect the state of the world when that method is invoked:

Of course, the impact of the deposit method is just to increase the balance of the first account by $75.00. This happens, and the piece of scratch paper for this method is thrown away, and control returns to the transferFrom method again:

At this point, there's nothing left to do in the transferFrom method, so we just throw its piece of paper away, resulting in the final state of the world:


Ben Dugan & UW-CSE, Copyright (c) 2001.