Post-increment x by n (n != 1)
Asked Answered
S

3

10

So, if I execute the following code...

int x = 0;
Debug.WriteLine(x++);
Debug.WriteLine(x += 4);
Debug.WriteLine(x);

... I get 0, 5, and 5, respectively. What I'd like to get, however is 0, 1, and 5. Is there any way to do a post-increment by n in C#? Or do I have to write out the += as its own statement?

Just for context, what I'm actually doing is a bunch of BitConverter operations on a buffer, and it'd be really nice to have each one as a self-sufficient statement where the offset is incremented by the size of the data type being converted to. That way, if the buffer format is later changed, I can just add or remove the one line without having to worry about any of the surrounding code.

Surmount answered 9/12, 2013 at 5:0 Comment(10)
I would say it's not possible.Remunerate
just so im clear, you want to post-increment by more than one?Crop
using your example you will never ever get a zero and a one together out of those three WriteLines.Skellum
Alden: Yes, that's what I want to do.Surmount
x++ is syntactic sugar for x += 1. This only works for +1, all others have to be done using += x.Cannelloni
Mine it is not an answer, rather a question 'cos I don't understand the point. Why not PRE-increment (++x) in order to achieve the "one"?Lackluster
@MarioVernari: then you'll never have 0 as output.Cannelloni
@JeroenVannevel: No, ++x is equivalent to x += 1. x++ can't be written using +=.Sepalous
@BenVoigt: you're right, that distinction got lost on me.Cannelloni
@JeroenVannevel: That distinction is the basis of this entire question.Sepalous
G
5

You should be able to abuse Interlocked.Exchange to get the old value of a variable while at the same time replacing its value:

Debug.WriteLine(Interlocked.Exchange(ref x, x+4));

in other words, replace the value of variable x with x + 4 but return the previous value of x.

Edit:

Disassembly shows this "increment by 4 and swap" is done in 4 instructions - no call needed at all, so performance should be good:

            Interlocked.Exchange(ref x, x + 4);
0000005e  mov         eax,dword ptr [rbp+2Ch] 
00000061  add         eax,4 
00000064  xchg        eax,dword ptr [rbp+2Ch] 
00000067  mov         dword ptr [rbp+28h],eax 

The non-intuitive nature of this (and other) solutions probably boils down to the violation of the CQS principle - we are mutating a variable and returning a value all at once, i.e. not something we should be doing in the mainstream.

Gompers answered 9/12, 2013 at 5:15 Comment(5)
This is very nice as well. Not intuitive, IMHO: you should spin a bit of brain in order to understand what the purpose of the line.Lackluster
And I just learned something new. I'll give it a try and see how it performs compared to just using x += 4 as a separate operation. After all, I can always write that as a statement at the end of the line and tell StyleCop what to go do with itself when it complains about multiple statements on one line. :) This is basically the heart of a long-running operation, though, so whatever's fastest wins!Surmount
Just tested it and the performance was on par with writing a custom function, but not surprisingly, slower than just adding the extra x += 4.Surmount
Interlocked operations are potentially far more expensive than needed here. Furthermore, they only work when one argument is a memory location. In code like this, x ought to be in a register. Not all 4 instruction sequences are created equal. I'd venture to guess the performance approaches a custom function only if that function doesn't get inlined.Sepalous
If you're going to call a method somewhere to do this job, I would rather go the route of creating a specialized method for this with a proper name.Hillis
R
4

As far as I know it's not possible. You could write your wrapper method like that:

static void ExecuteWithPost(ref int value, Action<int> operation, Func<int, int> postOperation)
{
    operation(value);
    value = postOperation(value);
}

and use it:

int i = 0;
ExecuteWithPost(ref i, x => Debug.WriteLine(x), x => x + 1);
ExecuteWithPost(ref i, x => Debug.WriteLine(x), x => x + 4);
ExecuteWithPost(ref i, x => Debug.WriteLine(x), x => x);

Prints what you want.

The wrapper method can be generic to make it work with types other than int:

static void ExecuteWithPost<T>(ref T value, Action<T> operation, Func<T, T> postOperation)
{
    operation(value);
    value = postOperation(value);
}
Remunerate answered 9/12, 2013 at 5:11 Comment(2)
An upvote by me: I'd write something like this. I only don't like the "ref", and I'd prefer to return the updated value. Just tastes, though.Lackluster
I thought of doing something like that, but figured it would probably add too much overhead. I like your solution, though, a lot more generic and elegant than mine would have been!Surmount
S
0

Operator ++ is short form of x = x + 1; so using += is not a bad idea:

If I understand you correctly:

int x = 0;
Debug.WriteLine(x++);  //return 0
Debug.WriteLine(x);  //return 1
Debug.WriteLine(x += 4);  //return 5

I would suggest you to use operator += because any other way operator overloading or something else; will just be a overhead.

Salomesalomi answered 9/12, 2013 at 5:6 Comment(1)
That's not a 'post-increment by 4' like x++, that's an increment by 4.Defalcation

© 2022 - 2024 — McMap. All rights reserved.