Search code examples
c#variablesmethodslinked-listassign

Why does a C# linked list class variable not retain its value after it's assigned?


I am creating a crossword puzzle generator and seem to have an issue with a simple variable assignment of co-ordinates in the grid system. I have a very simple structure to hold discrete coordinate values as seen below. I have stripped encapsulation to make it easier to read.

    public struct vec2
    {
        public int x, y;
        public vec2(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
    }

This Vec2 Structure is maintained inside a class to hold word values

public struct WordClass
{
    string svalue;
    bool flag;
    public vec2 position;

    public WordClass(string sarg, bool barg)
    {
        this.svalue = sarg;
        this.flag = barg;
        position = new vec2(0,0);
    }
    public string StringVal
    {
        get { return svalue; }
    }
    public bool FlagVal
    {
        get { return flag; }
    }
    public void DisableWord()
    {
        if (this.flipflop == false)
        {
            this.flipflop = true;
        }
    }
    public void SetPos(int xa, int ya)
    {
        this.position.x = xa;
        this.position.y = ya;
    }
}

This should basically maintain a list of permanent words with a flag for usage, and a variable position as the system calculates optimal locations for the word.

I have a dynamic linked list of words

    List<WordClass> WordList = new List<WordClass>();

and to change the coordinates of a word in the wordlist

    //Arbitrary values
    WordList[0].SetPos(Position_X, Position_Y);

Now my issue is that when I try to use the position of the word, no matter what I set it too prior, it maintains a default value of 0, 0. I have been scratching my head while doing other functionality, and it's left me wondering if I'm missing something important.


Solution

  • Problem seems to be related to the fact that vec2 is a ValueObject and you're trying to change it. The problematic lines are concretely those two:

    this.position.x = xa;
    this.position.y = ya;
    

    Why? Because vec2 is a a struct each time you read it you get a temporary copy, then modify that copy, then the copy is thrown away, while you're still reading the original, unmodified one. That's one reason why value objects should be immutable as much as possible, unless you've got a strong reason.

    The first step should be to make a proper immutable vec2 structure:

    public struct vec2
    {
        public int x { get; private set; }
        public int y { get; private set; }
    
        public vec2(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
    }
    

    Once you've got that, you need to take care of the modification in the SetPos method. Since the structure is immutable you can no longer read it, but instead each time you need to change it you'll throw the current instance away and create a new one:

    public void SetPos(int xa, int ya)
    {
        this.position = new vec2(xa, ya);
    }
    

    This creates a brand-new structure and assings it to the internal field, containing the new values. As this doesn't really attempts to modify the structure, but instead change the structure for a new one it won't be subject to the same subtle bug.