Local variable in recursion retaining values?

1.9k Views Asked by At

Currently working on recursion practice/implementation and noticed something that goes against everything I know to be true in programming.

Recursive method

protected int getArea() {

    if(width <= 0)
        return 0;
    else if(width == 1)
        return 1;
    else {

        Triangle t2 = new Triangle(width - 1);
        int area = t2.getArea();//Area variable somehow is holding the values of previous calls, despite being instantiated in each new call?

        return area + width;

    }

}

Somehow, the local variable, area, is aggregating values from previous calls in the recursive method. How is this possible, when with each call it is instantiated? In each call, it appears the method getArea() is called again, preventing the area variable from holding anything due to the fact the getArea() call happens before the methods return statement.

How is this happening?

3

There are 3 best solutions below

1
On BEST ANSWER

Each method call details are stored on stack, once the value is returned from the method call the execution returns to the previous method calling the current method, the local variable values,etc,. would be stored on the stack and that's how those values are used in the execution when required by program. Do some experimentation around recursive programs to understand more about it.

My suggestion would be try debugging recursive programs using break points on IDE's like eclipse or Intellij, it would clear a lot of confusion and brings clarity on how recursion works.

0
On

I think you are looking at this wrong. If you call two methods. eg.

public int test() {
    int x = getSomeInt(1);
    int y = getSomeInt(2);
    return x + y;
}

Are you ever questioning whether return x + y is done or if the value of x is determined before y? It does it from top to bottom and the statement setting y does not start before getSomeInt(1) has returned and its value set as x. So to your example:

protected int getArea() {
    if (width <= 0) {
        return 0;
    } elseif (width == 1) {
        return 1;
    } else {
        Triangle t2 = new Triangle(width - 1);
        int area = t2.getArea();
        return area + width;
    }
}

So if you have a Triangle with width 1 and call getArea you get 1 back.

What happens if you do it on a Triangle with width 2? Well it creates t2 with width 1 and call getArea on it. We already know the result since we calculated it already. area becomes 1 and then it returns 1 + 2.

What happens if you do it with width 3?. It will create t2 with width 2 and call getArea() on that. We know that returns 3 from the above and the result is 3 + 3.

The recusive method gets called with a high with, but it is the one with 1 that gets determined first, then 2, 3, 4, ...and finally the call you actually called has some area that it adds its with to.

Each call to a methoid has nothing to do with the callee. It is the same code yes, but it's a different object and the local variables are unique to the call just as the two calls getSomeInt also have two differen versions of whatever it called its first parameter. They are not entangled unless you are mutating or passing by reference.

Calling a method on an object is very similar to the object being an argument in the call. The recursive call has an object with a smaller width and at one point it will hit the base case. You could say this is the same:

public static int getArea(Triangle t) {
    if (t.width <= 0) {
        return 0;
    } elseif (t.width == 1) {
        return 1;
    } else {
        Triangle t2 = new Triangle(t.width - 1);
        int area = getArea(t2);
        return area + t.width;
    }
}

Again.. a method being recusive does not change anything. It ahs no special treatment. It needs its calls to finish before it can return the value, just like if you used a different method to get the area in getArea.. No difference at all.

0
On

When it comes to recursion, I often find it helpful to remember that what you give is what you get, meaning that what you get when you call your recursive method is whatever you decide to return from it.

In this case, what you get when you write

int area = t2.getArea();

is either 0, 1 or area + width.

The last case is the recursive case where you recursively define a new Triangle instance with the new width decremented 1 and then call .getArea() on that. That is functionally equivalent to just defining .getArea() as

protected int getArea(int width) {

    if(width <= 0)
        return 0;
    else if(width == 1)
        return 1;
    else {
        int area = getArea(width - 1);
        return area + width;
    }

}

It makes no difference whether you call .getArea() from one or the other instance of Triangle. All that matters is what you define width to be when calling it (in this case width - 1) and how you define its influence on the return value.