DEV Community

Discussion on: The difference between x++ and ++x

Collapse
 
xowap profile image
Rémy 🤖

Well good point on increment theoretically being a different operation than addition, however in practice I think in terms of produced bugs.

If you do stuff like

const a = ['a', 'b', 'c'];
let i = 0;

while (a[i] !== undefined) {
    doStuff(a[i++]);
}

At the moment you start digging into it and do some quick copy/pasta for debugging purposes:

const a = ['a', 'b', 'c'];
let i = 0;

while (a[i] !== undefined) {
    doStuff(a[i++]);
    console.log(a[i++]);
}

You're done because you've created a bug.

So I know you're going to explain to me all the rules to follow not to create bugs and the rigorous way you have to work with ++. However if you just don't use it then you don't need to use those rules and that's many less issues to load your head with. Also it's pretty easy to forbid it in the linter so you also help juniors not making mistakes.

Unlike what you said, the real issue is not that you can do both operations but rather that you're playing with side-effects. Neither of those operators are good.

In case you're curious about how it goes under the hood, I've compiled two example functions. A first one which does a ++:

char get_next_char_pp(char* str, int i) {
    return str[++i];
}

The produced ASM is the following

get_next_char_pp:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     DWORD PTR [rbp-12], esi
        add     DWORD PTR [rbp-12], 1
        mov     eax, DWORD PTR [rbp-12]
        movsx   rdx, eax
        mov     rax, QWORD PTR [rbp-8]
        add     rax, rdx
        movzx   eax, BYTE PTR [rax]
        pop     rbp
        ret

Now using the += 1 method:

char get_next_char_add(char *str, int i) {
    i += 1;
    return str[i];
}
get_next_char_add:
        push    rbp
        mov     rbp, rsp
        mov     QWORD PTR [rbp-8], rdi
        mov     DWORD PTR [rbp-12], esi
        add     DWORD PTR [rbp-12], 1
        mov     eax, DWORD PTR [rbp-12]
        movsx   rdx, eax
        mov     rax, QWORD PTR [rbp-8]
        add     rax, rdx
        movzx   eax, BYTE PTR [rax]
        pop     rbp
        ret

As you can see, CPU-wise it is totally identical. The compiler actually just splits your line in two implicitly. And as the Zen of Python says: Explicit is better than implicit.

Hence my strong advocacy against the ++ operator in any language. It is a useless and harmful operator, source of headaches and bugs.

Thread Thread
 
fpuffer profile image
Frank Puffer

Yes, the main issue is mutability. The ++ operator is actually a hidden assignment. In most modern languages there are few use cases for incrementing variables, mainly because they provide better ways for looping over collections. However I sometimes have to maintain legacy C code where I don't want to miss ++ in for loops.

I believe that += is only slightly better when it comes to copy/paste errors. You can also do this (at least in C++ and Java - not sure about JS):

while ( ... ) {
    doStuff(a[i += 1]);
    console.log(a[i += 1]);
}

But it looks weird and will hopefully be noticed soon.