
Stack: Where the method calls and local variables live. Heap: Where objects live
Essentially, both finds the closest declaration. x → b.this.x y → 2 (a copy stored in the A object through a = b.f()) b.this.x = 2 (accessed via reference)


long sum(long n, long result) {
if (n == 0) return result;
return sum(n - 1, n + result); // nothing left to do
after the call
}
This is like the iterative type of recursion. Tail-recursive: The recursive call is the very last action. Current stack frame is no longer needed once the recursive call is made.
long sum(long n) {
if (n == 0) return 0;
return n + sum(n - 1); // addition is done AFTER the
recursive call returns
}
Caller must still perform n + … after it returns. Each call must therefore keep its own stack frame alive. Causing O(n) stack frames to accumulate, leading to StackOverflowError.

abstract class Compute<T> {
public abstract boolean isRecursive();
public abstract Compute<T> recurse();
public abstract T evaluate();
public abstract T evaluate2();
}
// Base is the last part of Compute
class Base<T> extends Compute<T> {
private final Supplier<T> val;
public Base(Supplier<T> v) {
this.val = v;
}
// once reached base, no longer recursive
public boolean isRecursive() {
return false;
}
// there's nothing to recurse, so just return this
public Base<T> recurse() {
return this;
}
// get the final value
public T evaluate() {
return this.val.get();
}
public T evaluate2() {
return this.val.get();
}
}
// Recursive is a part of Compute
class Recursive<T> extends Compute<T> {
private final Supplier<Compute<T>> val;
public Recursive(Supplier<Compute<T>> v) {
this.val = v;
}
// while recursive, isRecursive
public boolean isRecursive() {
return true;
}
// activating it
public Compute<T> recurse() {
return this.val.get();
}
// unwrap one level and and calls evaluate (assumes base)
public T evaluate() {
Compute<T> v = this.val.get();
return v.evaluate();
}
// safer as it checks if it's a base
public T evaluate2() {
Compute<T> result = this.val.get();
while (result.isRecursive()) {
result = result.recurse();
}
return result.evaluate2();
}
}
Potential naivety
public T evaluate() {
Compute<T> v = this.val.get();
return v.evaluate();
}
// If not managed well,
// This is just normal recursion — each evaluate() call pushes a new stack frame. For large n, you get stack overflow!
The fix is to convert recursion into a loop
long sumit(long n, long result) {
while (n != 0) {
result = n + result;
n = n - 1;
}
return result;
}
// Instead of recursive method calls building up on the stack, you just update variables in place:
