when are class members set

I change a value of a member of a variable expecting it to be changed immediately however it looks like it is valid only on the next frame:
I managed to create a very small sample that reproduce the symptom:
one class that has the data:

public class Card : MonoBehaviour
{
    [SerializeField]
    private int mValue;

    public enum CoinState
    {
        NoCoin = 0,
        HasCoin,
        CoinPlaced
    }

    private CoinState mCoinState;

    public int Value
    {
        get
        {
            int aValue = mValue;
           
            if (mCoinState == CoinState.CoinPlaced)
            {
                mValue = 0; // this was the code in the original question
                aValue = 0; // is the right code that should be written and no problem happens
            }

            return aValue;
        }
    }

    public CoinState Coin
    {
        get { return mCoinState; }
        set { mCoinState = value; }
    }
}

And the second main class that use it:

public class Main : MonoBehaviour
{
    [SerializeField]
    private Card[] mCards;

    // Start is called before the first frame update
    void Start()
    {
        Debug.Log("Started");
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown("t"))
        {
            ExecuteTest();
        }
    }

    private void ExecuteTest()
    {
        // 4 cards are added to mCards values: 1,2,3,4
        int aBefore = SumOfCards();
        mCards[0].Coin = Card.CoinState.CoinPlaced;
        mCards[2].Coin = Card.CoinState.CoinPlaced;
        int aAfter = SumOfCards();
        Debug.Log("Before:" + aBefore + " After:" + aAfter + "," + SumOfCards());
    }

    public int SumOfCards()
    {
        int aSum = 0;

        for (int aCard = 0; aCard < mCards.GetLength(0); aCard++)
        {
            aSum += mCards[aCard].Value;
        }

        return aSum;
    }
}

The problem is in the Execute Test function:
if you look at what I expected to see in the Debug.Log output I’d expect to see that the value of aAfter and
SumOfCards(); that is printed right after it to be the same, but they are not.
for example if I give 4 cards the values of 1,2,3,4 (card[0] = 1, etc) the aBefore is 10, the aAfter is also 10 but SumOfCards printer right after is the correct one of 6.
The correct value is only printed if I use Debug.Log or only in the next frame.
Why is that?
I expected the card members to be updated right after I set the member, so when I use it I’ll get ‘Value’ function I’ll get the correct answer.

In the Value getter, you are copying mValue to aValue, set the new value in mValue when the CoinState is “CoinPlaced”, but return the old value aValue.

Because of this the value is the old one when the getter is called the first time after changing the CoinState to “CoinPlaced”, the second time the getter is called the value is 0.

Maybe your intention was to set aValue to 0 when the CoinState is “Placed” in the getter to keep the original value of the card in mValue.

This updates the value immediately upon setting the CoinState:

   public int Value
    {
        get
        {
            return mValue;
        }
    }

    public CoinState Coin
    {
        get { return mCoinState; }
        set
        {
            mCoinState = value;

            if (mCoinState == CoinState.CoinPlaced)
            {
                mValue = 0;
            }
        }
    }

1: @dk404 In your answer the original mValue is lost. so if I reset the mCoinState to NoCoin I can’t restore the original mValue.
2: I figured that in the getter I’m copying the old value, the question is why. Since the set of coin state is done before the get of the value. so when I’m going the get the if statement should already check the coin state correctly and give me the correct answer.

Well, I don’t quite understand the question because your description of your result is clearly wrong. You can not get the result that you claim you get.

However just to make this 100% clear, when I copy your code verbatim I get:

202191-cardtestresults.png

So just as we would expect we get 10, 6, 6. Though your code has those two comments which makes it quite unclear what exact code you’re using and what’s the exact repo case you talked about. I get exactly what we all would expect.

IF you meant that your property getter looked like this:

     public int Value
     {
         get
         {
             int aValue = mValue;
            
             if (mCoinState == CoinState.CoinPlaced)
             {
                 mValue = 0; // this was the code in the original question
             }
 
             return aValue;
         }
     }

Then yes, you would get 10, 10, 6 just as expected. Maybe this is your problem? Maybe you didn’t get the point or nature of properties in the first place? Properties are just methods. Properties itself do not store any data themselfs (with the exception of auto-properties which automatically declare a hidden backing field for you). So if your getter looks like this, you still set the actual field immediately to 0, but the getter still returns the old value when first called after you changed the coin state. However, after this first call the private field mValue is now set to 0 so a second call to the method would now return 0. That’s all and exactly what you would expect.

Just to make this 100% clear: There are only two fields which can actually store information in your Card class and those are “mValue” and “mCoinState”. The properties are just methods. They don’t have any state on their own.

You said:

In your answer the original mValue is lost.

Well, of course. If you set mValue to 0, it is set to 0, so of course the original value is lost. Maybe you wanted to do something like this:

     public int Value
     {
         get
         {
             if (mCoinState == CoinState.CoinPlaced)
             {
                 return 0;
             }
             return mValue;
         }
     }

So the property would return 0 if the coin state is “CoinPlaced”. However the card of course keeps it’s own internal value. If you change the coin state again, you would get the old value again.

Your original code essentially violates a core principle for property getters: No unexpected side effects! Properties should be treated “as if” they are variables. So any unexpected behaviour should be avoided, especially in the getter. The getter should never have mutating behaviour in it. If certain clamping is necessary, this should be done in the setter. Though in your case your property is a read only getter. So don’t modify the state of the class in the body of a getter.

See the guidelines for properties. It’s completely fine if a property getter does calculate the actual return value “on the fly” based on the object state, but it should never change the state. So subsequent calls to the getter should always return the same value unless the state of the object was changed in between.

TLDR: Do not have mutating / “state changing” code inside a getter of a property.