Method calls and how they work

If you are like most beginning programmers, you probably find the whole bit about method calls a bit fuzzy. Sometimes they return something, sometimes they do not, what are parameters really, and why are the values you pass sometimes modified in the calling method, and sometimes not? These are just some of the questions you may have, but fear not, at the end of this brief article, you should be able to answer these questions and more too!

Because a method call is kinda like a phone call. Also I wanted to catch your attention (by: Da Sal under a CC-BY 2.0 license)

Return types

We are going to start with the end first, so to speak, namely returning values from methods, or functions as some programming languages (like P-code) like to call them.

In most programming languages, for example Java, you return a value using the return keyword. But what does that really mean, and why return? Return to where?

This comes from the idea that a method call is really a transfer of control of the program. When you call a method, say it is call addNumbers, what you really do is that you perform a go-to. You say go to that location where addNumbers is defined. When you write return, it means return from the current method, to where the last method call was made from. When you write a value it means, please bring this value along to where the method call was made from.

For example:

Figure 1: MethodCall1 example showing a simple method call.

I am going to put the line numbers in square parentheses in the following:

In the class MethodCall1 we see first three variables, x, y, z [4–6] defined with different integer values. Then we do a method call to addNumbers with the parameters x and y [8]. addNumbers then calculates the result and returns it. When it encounters the return statement, it knows (I will explain why later) where it was called from, and it is going back to there with the result. Unfortunately, if we wanted to save it, we have not assigned the return value of the method to anything, so it is lost.

Then on the next line [9] we have a call again, but with different parameters, y and z. The same thing happens, but when the return keyword is encountered it knows that it came from line 9 and returns there. This time the result is assigned to the variable res. Note that the res here is completely independent of the res defined in addNumbers that is, they are each local, and could have been named anything and the code would still work.

Passing parameters by value

So what does it mean to pass a parameter? It usually means that the value of a variable is copied to the method which is being called, which can then name it whatever it wants.

For example in Figure 1, we can see that the parameters are named a and b, but we call it with x, y, and z. How does that work? How does it know how to name what? There is a simple algorithm that most programming languages follow:

  1. Substitute parameters at call site. It just means that if it is a variable, put the value, so for the call at line 8 it becomes addNumbers(5,2).
  2. Copy the variables and assign them to local variables. This happens using something called the call stack, but you can imagine that in the beginning of the method a line for each parameter is inserted like this:
    int a = 5;
    int b = 2;

    You may wonder how it knows which is which, and this is purely from the ordering. So the method signature is addNumbers(int a, int b), meaning that first a is passed, then b. So whatever is first becomes a and whatever is second becomes b.

Passing parameters by reference

This is mostly relevant in languages where you can modify values or objects after they are declared, for example Java.

In Java variables can contain values or objects, and most of the time that distinction does not matter so much, but it is crucial when understanding parameter passing, because when you are passing an object, you are really passing a reference to the object. To understand what this means we have to look a bit at how memory is actually used inside the program.

When you define a variable to be, for example, an instance of some class, it really means that you are allocating some memory, meaning that you are asking for some memory to be made available by the operating system, to store this instance.

Every place in memory has an address which is just a number, but you can think of it as a street, where each house has a number and in each house you can store an instance. Then when you want to get to the instance you just go to house number 27 and get it.

When you pass by reference it means that instead of copying the object like we saw before with the integers, you instead copy the address of the object. An example could be an array in Java. When you use an array as a parameter it is not copied, just the address is. That also means that if you modify the array in the method you are called, you are going into the house and modifying the original array.

For example:

Figure 2: MethodCall2.java demonstrating call-by-reference

In this case we declare two variables, xs and ys, which are two arrays, each of three integers [4-5]. Then we call the method addNumbers twice, with the two arrays as parameters [7–8] and finally we print out each element in xs on its own line [10–12].

Inside addNumbers we take two arrays as parameters, as and bs, but in this case the algorithm for passing parameters is different:

  1. We still do a substitution, but really we pass the address so in pseudo-code it looks like this:
    addNumbers(addressof(xs), addressof(ys)), meaning that we give the addresses as parameters of the two arrays. Remember that the address is just like a house address, so it is just a number identifying the location of something.
  2. Then we assign the addresses to the two variables as and bs, like:
    int[] as = addressof(xs)
    int[] bs = addressof(ys)

This means that when we write as[i] = as[i] + bs[i]; what really happens is this:

  1. On the right hand side: Look up whatever is at the address of as[i] and at the address of bs[i] and add them together.
  2. Then, on the left hand side, go to the address (again) of as[i] and assign the value of the right hand side.

Notice that the addNumbers method is void, meaning that it does not return a value. It does not even have an explicit return statement, even though it has an implicit(not written) one at the end automatically, so that it can get back to wherever it was called from. If it was written it would be after the } on line 21.

Stay tuned when we go a step deeper in the next article and look at the call stack!

--

--