What's the correct way to implement operator ++ for value-types?
Asked Answered
P

4

5

I'm working on a custom implementation of a Number struct, with very different ways of storing and manipulating numeric values.

The struct is fully immutable - all fields are implemented as readonly

I'm trying to implement the ++ and -- operators, and I've run into a little confusion:
How do you perform the assignment?
Or does the platform handle this automatically, and I just need to return n + 1?

public struct Number
{
    // ...
    // ... readonly fields and properties ...
    // ... other implementations ...
    // ...

    // Empty placeholder + operator, since the actual method of addition is not important.
    public static Number operator +(Number n, int value)
    {
        // Perform addition and return sum
        // The Number struct is immutable, so this technically returns a new Number value.
    }

    // ERROR here: "ref and out are not valid in this context"
    public static Number operator ++(ref Number n)
    {
        // ref seems to be required,
        // otherwise this assignment doesn't affect the original variable?
        n = n + 1;
        return n;
    }
}

EDIT: I think this is not a duplicate of other questions about increment and decrement operators, since this involves value-types which behave differently than classes in this context. I understand similar rules apply regarding ++ and --, but I believe the context of this question is different enough, and nuanced enough, to stand on its own.

Prewitt answered 17/12, 2015 at 19:17 Comment(1)
Possible duplicate of How to implement pre and post-increment / decrement operator in my class?Pet
S
10

The struct is fully immutable - all fields are implemented as readonly

Good!

I'm trying to implement the ++ and -- operators, and I've run into a little confusion: How do you perform the assignment?

You don't. Remember what the ++ operator does. Whether it is prefix or postfix it:

  • fetches the original value of the operand
  • computes the value of the successor
  • stores the successor
  • produces either the original value or the successor

The only part of that process that the C# compiler does not know how to do for your type is "compute the successor", so that's what your overridden ++ operator should do. Just return the successor; let the compiler deal with figuring out how to make the assignment.

Or does the platform handle this automatically, and I just need to return n + 1?

Yes, do that.

Suetonius answered 17/12, 2015 at 19:31 Comment(0)
C
1

The statement num++; by itself expands to num = PlusPlusOperator(num);. Since your data type is immutable, just return n+1; and the compiler will handle the rest.

Concelebrate answered 17/12, 2015 at 19:30 Comment(3)
Your first sentence is inaccurate. The return value of num++ is the original value, not the return value of PlusPlusOperator(num). The lazy oversimplification (which is still inaccurate) is to claim that num++ returns the value before performing the increment. See Eric Lippert's answer for the accurate answer. Eric Lippert goes into more detail here. Be warned that the accepted answer to that question is wrong.Coleville
@Brian: No, the first sentence is accurate though I see why you think it isn't., The sentence states that the statement num++; is an assignment of the increment operator result to the original variable, which it is. Had SaxxonPike said that the expression num++ was simply that, that would be wrong. But the compiler is perfectly within its rights to generate the statement form as though it were simply an assignment because the value -- the original value of the variable -- is discarded. That said, I agree that this answer is misleading; that semi is subtle.Suetonius
Thanks for the feedback. I've edited my answer to be more clear. "Statement" is the word I should have used.Concelebrate
V
1

The processing of ++ and -- operators is described in C# language specification, section 7.7.5 Prefix increment and decrement operators:

The run-time processing of a prefix increment or decrement operation of the form ++x or --x consists of the following steps:

• If x is classified as a variable:

  o x is evaluated to produce the variable.

  o The selected operator is invoked with the value of x as its argument.

  o The value returned by the operator is stored in the location given by the evaluation of x.

  o The value returned by the operator becomes the result of the operation.

So a custom overloads of these operators only need to produce an incremented/decremented value. The rest is handled by the compiler.

Volkan answered 17/12, 2015 at 19:40 Comment(0)
P
0

A Number class is going to have a value of some kind as a property.

public static Number operator ++(Number n)
{
    // ref seems to be required,
    // otherwise this assignment doesn't affect the original variable?
    n.value = n.value + 1;
    return n;
}

This should do what you want.

I wrote this using your struc and added the value property.

private static void Main(string[] args)
{
    var x = new Number();
    x.value = 3;
    x++;
    Console.WriteLine(x.value);
    Console.Read();
}

This properly generates a 4

Prying answered 17/12, 2015 at 19:26 Comment(1)
You missed one detail, the struct is immutable, so you can't assign the value field like that. :)Prewitt

© 2022 - 2024 — McMap. All rights reserved.