views:

1847

answers:

18
+21  Q: 

x=x+1 vs. x +=1

I'm under the impression that these two commands result in the same end, namely incrementing X by 1 but that the latter is probably more efficient.

If this is not correct, please explain the diff.

If it is correct, why should the latter be more efficient? Shouldn't they both compile to the same IL?

Thanks.

+11  A: 

IMPORTANT:

The answers specifying evaluation are certainly correct in terms of what a += do, in general languages. But in VB.NET, I assume X specified in the OP is a variable or a property.


They'll probably compile to the same IL.

UPDATE (to address the probably controversy):

VB.NET is a specification of a programming language. Any compiler that conforms to what's defined in the spec can be a VB.NET implementation. If you edit the source code of the MS VB.NET compiler to generate crappy code for X += 1 case, you'll still conform to VB.NET spec (because it didn't say anything about how it's going to work. It just says the effect will be exactly the same, which makes it logical to generate the same code, indeed).

While the compiler is very very likely (and I feel it really does) generate the same code for both, but it's pretty complex piece of software. Heck, you can't even guarantee that a compiler generates the exact same code when the same code is compiled twice!

What you can feel 100% secure to say (unless you know the source code of the compiler intimately) is that a good compiler should generate the same code, performance-wise, which might or might not be the exact same code.

Mehrdad Afshari
+1 Not just "probably", they do :)
Andrew Hare
Who knows? The spec just guarantees that they do the same thing. There's no guarantee they'll generate the same IL, though! So, technically, it's possible to build a compiler that doesn't generate the exact same IL for these two. That's why I wrote probably.
Mehrdad Afshari
"Probably" doesn't cut it.
Sung Meister
Never be that sure about a compiler that generates optimized code. While it'll most likely translate it to the same thing, it might trigger a different code path in the compiler and *might* eventually change the results so that's it wouldn't be *exactly* the same.
Mehrdad Afshari
@Mehrdad - Good point about different compiler implementations, I didn't think of that. It may be worth moving some or all of your explanation into your answer as it is an interesting topic.
Andrew Hare
+18  A: 

they compile to the same, the second is just easier to type.

yx
And generally easier to read.
Chris Lively
See Dennis Palmer's answer, from MSDN they do not compile the same, so this answer is incorrect.
Steve Mitcham
Dennis Palmers answer is more accurate: The x will only be evaluated once. So if you have x.Member.Property(index).Field += y, the whole thing in front of += is stored in between getting the old value and setting the new value.
SealedSun
@SealedSun: The question does specify X += 1. Not X() += 1 or X.Y() += 1. So you can assume X is a property or a variable. Can you give an example that they are not equal, given this assumption?
Mehrdad Afshari
Turns out @yx was correct. I got confused with the MSDN library and was looking at the description of += for JScript. doh! I updated my answer with the correct link as well as a sample app.
Dennis Palmer
A: 

At run time (at least with PERL) there is no difference. x+=1 is roughly .5 seconds faster to type than x = x+1 though

Brian
Q is tagged VB.NET.
Mehrdad Afshari
Yeah I know. Didn't set up the machine I was working on to run MSFT projects.
Brian
+2  A: 

They may be the same in VB; they are not necessarily the same in C (where the operator comes from).

McWafflestix
This opcode is why many programming languages have a ++ operator. The IL is generates is not as important as the native code that the JIT creates.
Matthew Whited
+2  A: 
  1. Yes, they behave the same.
  2. No, they are probably equally efficient. Optimizers are good at that sort of thing. If you'd like to double check, write the optimized code and view it in reflector.
Greg D
+2  A: 

The optimizer probably produces the same result, if x is a simple type like int or float.

If you'd use some other language (limited VB knowledge here, can you overload +=?) where x could be one big honking object, the former creates and extra copy, which can be hundreds of megs. The latter does not.

Marcus Lindblom
In any modern compiler, the optimizer WILL make them the same. In certain older compilers (ones that don't optimize!) they will be different, but will have the same effect (increment x).
Michael Kohne
I always use 'probably' around optimizers, cause one shouldn't assume anything. Then again, if x=x+1 where x is int is your biggest performance issue, I'd say you'd be pretty unique. :)
Marcus Lindblom
A: 

There is no difference in programmatic efficiency; just typing efficiency.

Andrew
+2  A: 

are the same.

x=x+1

is mathematical seen a contradiction whereas

x+=1

isn't and is light to be typed.

Luixv
mathoverflow.com?
Joe Philllips
+= is seen as non-existent in math I think...
Joe Philllips
Interesting point: functional languages (closer to math) won't have the compound assignment!
xtofl
+4  A: 

On x86, if x is in register eax, they will both result in something like

inc eax;

So you're right, after some compilation stage, the IL will be the same.

There's a whole class of questions like this that can be answered with "trust your optimizer."

The famous myth is that
x++;
is less efficient than
++x;
because it has to store a temporary value. If you never use the temporary value, the optimizer will remove that store.

Drew Hoskins
I once wrote a compiler specifically to perform 89 extra operations on x++ just for fun.
Joe Philllips
I thought Jon Skeet wrote that :)
Eduardo Molteni
++x IS more efficient if x is a C++ iterator
Milan Babuškov
If by "IS" you mean "can be if the optimizer doesn't inline the method and eliminate unnecessary work." Modern optimizers do whole program optimization and inline even cross-module, so the set of circumstances in which this matters is ever-decreasing.
Drew Hoskins
A: 

Back in the early 1980s, one of the really cool optimizations of the Lattice C Compiler was that "x = x + 1;", "x += 1;" and "x++;" all produced exactly the same machine code. If they could do it, a compiler written in this millenium should definitely be able to do it.

Paul Tomblin
It should have done something different for post-increment!
xtofl
Not if that was the entire statement. Sure, it would need to do something else if it was "y = x++;", but it detected that the side effect wasn't needed and optimized it away. That's one of the things that was so impressive in 1983.
Paul Tomblin
@xtofl, there's no reason for the compiler to do something different on post-increment if the return value of the post-increment isn't used.
Iceman
+81  A: 

From the MSDN library for +=:

Using this operator is almost the same as specifying result = result + expression, except that result is only evaluated once.

So they are not identical and that is why x += 1 will be more efficient.

Update: I just noticed that my MSDN Library link was to the JScript page instead of the VB page, which does not contain the same quote.

Therefore upon further research and testing, that answer does not apply to VB.NET. I was wrong. Here is a sample console app:

Module Module1

Sub Main()
    Dim x = 0
    Console.WriteLine(PlusEqual1(x))
    Console.WriteLine(Add1(x))
    Console.WriteLine(PlusEqual2(x))
    Console.WriteLine(Add2(x))
    Console.ReadLine()
End Sub

Public Function PlusEqual1(ByVal x As Integer) As Integer
    x += 1
    Return x
End Function

Public Function Add1(ByVal x As Integer) As Integer
    x = x + 1
    Return x
End Function

Public Function PlusEqual2(ByVal x As Integer) As Integer
    x += 2
    Return x
End Function

Public Function Add2(ByVal x As Integer) As Integer
    x = x + 2
    Return x
End Function

End Module

IL for both PlusEqual1 and Add1 are indeed identical:

.method public static int32 Add1(int32 x) cil managed
{
.maxstack 2
.locals init (
    [0] int32 Add1)
L_0000: nop 
L_0001: ldarg.0 
L_0002: ldc.i4.1 
L_0003: add.ovf 
L_0004: starg.s x
L_0006: ldarg.0 
L_0007: stloc.0 
L_0008: br.s L_000a
L_000a: ldloc.0 
L_000b: ret 
}

The IL for PlusEqual2 and Add2 are nearly identical to that as well:

.method public static int32 Add2(int32 x) cil managed
{ 
.maxstack 2
.locals init (
    [0] int32 Add2)
L_0000: nop 
L_0001: ldarg.0 
L_0002: ldc.i4.2 
L_0003: add.ovf 
L_0004: starg.s x
L_0006: ldarg.0 
L_0007: stloc.0 
L_0008: br.s L_000a
L_000a: ldloc.0 
L_000b: ret 
}
Dennis Palmer
Impressive... Actual research instead of just guesswork :) +1
Andrew Rollings
I find it hard to believe that the compiler would not optimize it into inc [x]. This is an easy peephole optimization. Can anyone benchmark this to find out?
Unknown
what about better performance has y-=20 over y-=19?
01
Created an app and disassembled. The functions were identical in IL. How can the documentation be correct if the IL generated for each operation is identical?
Gary.Ray
so after all that fuss, I was correct :)I applaud your excellent detective work and effort though. Would give more than +1 if I could.
yx
Note that strictly speaking the answer depends not on the language, but on the compiler used - although I have no doubt that Mono's VB.NET compiler behaves the same way.
reinierpost
+21  A: 

I wrote a simple console app:

static void Main(string[] args)
{
    int i = 0;
    i += 1;
    i = i + 1;
    Console.WriteLine(i);
}

I disassembled it using Reflector and here's what i got:

private static void Main(string[] args)
{
    int i = 0;
    i++;
    i++;
    Console.WriteLine(i);
}

They are the same.

Vinicius
And how is this helpful?
Joe Philllips
+1 for actual research and test
Eduardo Molteni
So, the example was incrementing by 1, but I looked at the question as more an issue of the operator's efficiency in general.How does the code disassemble if it's i += 2 and i = i + 2?
Dennis Palmer
As noted by @Mehrdad above, the question is tagged vb.net, so i++ doesn't exist. I'm curious what the vb version of your code disassembles to. Heading to dowlnoad http://www.red-gate.com/products/reflector right now.
Dennis Palmer
The shadows of spheres and cylinders can both be circles. It's not because it happens to compile to the same code that is's semantically equal.
xtofl
from the Java Language Specification, the difference lies in the number of times x+1 is evaluated: "A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T)((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once. Note that the implied cast to type T"Which proves your statement wrong for Java.
xtofl
+8  A: 

So many speculations! Even the conclusion with the Reflector thingy is not necessarily true because it can do optimizations while dissassembling.

So why does none of you guys just have a look into the IL code? Have a look at the following C# programme:

static void Main(string[] args)
{
    int x = 2;
    int y = 3;
    x += 1;
    y = y + 1;
    Console.WriteLine(x);
    Console.WriteLine(y);
}

This code snippet compiles to:

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 25 (0x19)
.maxstack 2
.locals init ([0] int32 x,
[1] int32 y)
// some commands omitted here

IL_0004: ldloc.0
IL_0005: ldc.i4.1
IL_0006: add
IL_0007: stloc.0

IL_0008: ldloc.1
IL_0009: ldc.i4.1
IL_000a: add
IL_000b: stloc.1

// some commands omitted here
}

As you can see, it's in fact absolutely the same. And why is it? Because IL's purpose is to tell what to do, not how to. The optimization will be a job of the JIT compiler. Btw it's the same in VB.Net

"IL's purpose is to tell what to do, not how to" and "The optimization will be a job of the JIT compiler" are both wrong. The high level language compiler also does optimization and IL is pretty much low level and says how rather than why.
Mehrdad Afshari
+1  A: 

In C++ it depends what datatype is x and how are operators defined. If x is an instance of some class you can get completely different results.

Or maybe you should fix the question and specify that x is an integer or whatever.

Milan Babuškov
i completely agree. it depends from the datatype, either in C and other languages as Java and C#
DaDa
+1  A: 

i thought the differences are due to the additional clock cycles used for memory references, but i turned out to be wrong! can't understand this thing myself

instruction type        example                      cycles

===================================================================

ADD reg,reg             add ax,bx                       1
ADD mem,reg             add total, cx                   3
ADD reg,mem             add cx,incr                     2
ADD reg,immed           add bx,6                        1
ADD mem,immed           add pointers[bx][si],6          3
ADD accum,immed         add ax,10                       1

INC reg                 inc bx                          1
INC mem                 inc vpage                       3

MOV reg,reg             mov bp,sp                       1
MOV mem,reg             mov array[di],bx                1
MOV reg,mem             mov bx,pointer                  1
MOV mem,immed           mov [bx],15                     1
MOV reg,immed           mov cx,256                      1
MOV mem,accum           mov total,ax                    1
MOV accum,mem           mov al,string                   1
MOV segreg,reg16        mov ds,ax                       2, 3
MOV segreg,mem16        mov es,psp                      2, 3
MOV reg16,segreg        mov ax,ds                       1
MOV mem16,segreg        mov stack_save,ss               1
MOV reg32,controlreg    mov eax,cr0                     22
                        mov eax,cr2                     12
                        mov eax,cr3                     21, 46
                        mov eax,cr4                     14
MOV controlreg,reg32    mov cr0,eax                     4
MOV reg32,debugreg      mov edx,dr0                     DR0-DR3,DR6,DR7=11;
                                                        DR4,DR5=12 
MOV debugreg,reg32      mov dr0,ecx                     DR0-DR3,DR6,DR7=11;
                                                        DR4,DR5=12

source:http://turkish_rational.tripod.com/trdos/pentium.txt

the instructions may be tranlated as:

;for i = i+1   ; cycles
mov  ax,   [i]  ; 1
add  ax,   1    ; 1
mov  [i],  ax   ; 1

;for i += 1
; dunno the syntax of instruction. it should be the pointers one :S     

;for i++
inc  i          ; 3
;or
mov  ax,   [i]  ; 1
inc  ax         ; 1
mov  [i],  ax   ; 1

;for ++i
mov  ax,   [i]  ; 1
;do  stuff      ; matters not
inc  ax         ; 1
mov  [i],  ax   ; 1

all turn out to be same :S its just some data that may be helpful. please comment!

xenodevil
i personally think, though i have never read any such thing, that inc takes less time than others, because its such a common instruction... for instatnce, values of PC and IR etc need to be INCed so often so there may be some faster mechanism for incrementing...
xenodevil
A: 

In a non-functional language, the operator '=' has to be always thought of as "assigned" not "equals"

A decent language (like Pascal (grin)) will use a symbol like ':=' or '<-' to differentiate it from '='

(by the way, this should have gone in as a comment but apparently I don't have a good enough reputation to be allowed to make comments (sigh))

are the same.

x=x+1

is mathematical seen a contradiction whereas

David
... not finishing a non-comment won't help your non-reputation.
reinierpost
A: 

Something worth noting is that +=, -=, *= etc. do an implicit cast.

int i = 0;
i = i + 5.5; // doesn't compile.
i += 5.5; // compiles.
Peter Lawrey
A: 

If x is a simple integer scalar variable, they should be the same.

If x is a large expression, possibly with side effects, +=1 and ++ should be twice as fast.

Many people concentrate on this kind of low-level optimization as if that's what optimization is all about. I assume you know it's a much bigger subject.

Mike Dunlavey