Why does the increment/decrement operator cause bugs when used in a recursive function?

Hello,
I have a question about the behavior of the increment/decrement operator in recursive functions.
Here’s a tree fractal pattern:

function setup() {
  ...
  angleMode(DEGREES);
}

function draw() {
  ...
  drawBranch(width/2, height,0, 3);
}

function drawBranch(x, y, agl, n){
  let x1 = x - 50*sin(agl); 
  let y1 = y - 50*cos(agl);
  line(x, y, x1, y1); 
  if(n > 1){
    drawBranch(x1, y1, agl-30, n--); 
    drawBranch(x1, y1, agl+30, n--); 
  }
}

Instead of a symmetrical tree, using n-- results in an issue where the branches are not drawn symmetrically, as shown here:

I fixed this by explicitly using n - 1 instead of n-- in the recursive calls:

function drawBranch(x, y, agl, n){
 ...
  if(n > 1){
    drawBranch(x1, y1, agl-15, n-1); 
    drawBranch(x1, y1, agl+15, n-1); 
  }
}

With this change, the tree is drawn correctly. Could anyone explain why the n-- caused this issue in the first place?

Thanks !

Hi @WaningJupiter,

Sorry, but isn’t that obvious? Just joking :slight_smile:

n-- stands for n=n-1

After each operation of n--, n is changing and you doing it twice in your code. So, for the first call of drawBranch, ‘n’ is used and changed and on the second call it uses that changed value (and change further).
Your solution is the proper way to do in this case! :+1:

Hope that helps to clarify…

Cheers
— mnse

PS: this is not related to recursion, you would have the same in other cases.

EDIT: add JavaScript doc

Actually, for java (but good explanation though)
Increment (++) and Decrement (–) Operators in Java Explained

2 Likes

Hello, @mnse
Thank you for the link, :grinning: . I hope this will help others who run into the same problem.

1 Like

Actually it is the pre-decrement version --n which is equivalent to n = n - 1 or n -= 1.

The post-decrement n-- has no true equivalent, b/c even though it also decreases the value of n by 1, it still evaluates as the original value of n.

1 Like

Oh… I had always assumed that n-- and --n are the same thing and I often would decide on a whim which variation I’d use. But thinking about it, this is not the type of looseness that a programming language would offer…

Which one of these is the “proper” format? Or do each of them have their respective use-cases?

1 Like

--n says to decrement first and then use the value. n-- says to use the value and then decrement afterwards. Consider

int n = 5;
int x = n--;
println( n, x );   // prints 4, 5

n = 5;
x = --n;
println( n, x );   // prints 4, 4

Both are correct and each has its use depending what you need. As stand-alone code, n--; is probably more common, but no more proper than the other.

3 Likes

Hi @GoToLoop ,

I would only partially agree. :slight_smile:
The operation is the same in both cases, just the utilisation of n differs in the operation.

From my context, I described the sequence of the operation for n-- in this case…

But could had a afterwards in addition to be more precise. :wink:

Cheers
— mnse

We should also note that these increments and decrements are evaluated as they occur within expressions. For instance, try to figure out what this code will print:

int x = 5;
int y = x++ - x + --x;
println(x, y);
3 Likes

You know… up until this day, I never gave this two thoughts. And everything worked just fine. But now that I’ve been thinking about your example I feel that everything I know about programming is beginning to unravel.

I’ve always operated with the assumption “The right side of a statement gets evaluated and then assigned to the left side”:

int a = 1;
int b = 2;
int c = a + b;
println(c); // 3

Therefore, in your example I would have bet a lot on x being 4.

int n = 5;
int x = n--;
println( n, x );

To me – a self-taught hobby-coder with no CS background – n-- is one unit. It makes the value of n “one smaller” and only afterwards that expression evaluation gets assigned to the left side of the statement. The notion that it’s different is somewhat concerning to me. The idea that this n-- “unit” is split into separate operations is weird.

n-- by itself reads to me as “n is one smaller”
but int x = n--; now reads “assign n to x and then make n one smaller”
This is very unintuitive to me.

The question is: in what conceptual way does the expression a+b differ from the expression n--? To me this is the same idea…

~A few hours later~

Answering my own question:

I’ve read into this a little and learned about purity, state modification and side effects.

a+b is a pure expression, meaning it does not alter the program state. This expression has no side effects.

n-- is an impure expression, because it affects the state of the program by modifying n. This expression has a side effec, i.e. making n one smallert.

I also understand that this is something that’s more relevant in Functional Programming.
Still, something I need to adjust my previous assumptions on.

Thanks for the comment and insights!

1 Like

Hello again,

I accidentally posted a code snippet in p5.js :sweat_smile:, but the code was originally written in Processing. Thanks for correcting my tag!

I add a follow-up here for Java and JavaScript, I may assume the post increment and decrement operators behave the same way in both Java and JavaScript.

int n = 5; 
println(n--); // returns 5, n-- is a shorthand of n = n-1, it's an assignement, so n's value will change; 
println(n); // returns 4, n has been assigned a new value by n -1; 
int n = 5; 
println(n-1); // returns 4, n-1 is an expression, not an assignement, this won't change the value of n, 
println(n); // returns 5, n will not change, 

In my original code, I called two functions in succession by using n--, that’s the reason of the bug :

if(n > 1){
 drawBranch(x1, y1, agl-15, n--); //At this line, n is assigned then updated to n - 1, its value has changed before being passed into the second function.
 drawBranch(x1, y1, agl+15, n--); 
  }

Thanks a lot for the helpful discussion, everyone!

1 Like