2

Okay, I've got a List<SpecialTile> called SpecialTiles where SpecialTile is a struct. One of the attributes of the SpecialTile struct is a public boolean value called Active that I'm trying to change, but it doesn't work for some reason. I'm not sure if it's relevant, but the list is owned by an instance of another class. Here's a picture when I ran it through the debugger:

Impossible?

So anyway, I ran into this problem because originally I tried to use the line of code

Mgen.SpecialTiles[ESV.editThis].Active = !Mgen.SpecialTiles[ESV.editThis].Active;

but it told me that "Active" was not a variable. As you can see it won't let me modify the value that way:

Still Impossible?

So I assumed that I'd have to modify the value through a method. But apparently that doesn't work either?

Am I missing something about List variables? And even if it's not supposed to modify the value, why would the debugger list "Active" as false and then flip it back to true?

Thanks!

Community
  • 1
  • 1
Superdoggy
  • 218
  • 1
  • 11

2 Answers2

5

This is an issue with structs. Calling the list indexer MGen.SpecialTiles[x] returns a copy of the structure stored in the list, so any method you call on that struct will operate on the copy. And since the copy is temporary, the changes made by that method ultimately end up being discarded.

If you change SpecialData to a class this should resolve your issue.

Erik
  • 5,355
  • 25
  • 39
4

This variable is not stubborn. You misunderstood/didnt notice that structs are special.

Structs are handled by value, not by reference.

When you write:

foo.mystructList[5]

you are referring to an item of an List. But since that List does not hold objects - this indexing returns you a copy.

Consider this:

var temp = foo.mystructList[5]
temp.flip()

would you now expect the 'flip()' to work? remember that the List holds structs. Surely, you wouldn't consider it to work, since you are flipping a copy.

Now back to your case:

foo.mystructList[5].flip()

that's the same as above! I just eliminated the temporary variable, but inside, that's the same. List is read, copy is returned, the flip is called on the copy.

Here:

foo.mystructList[5].prop = true

the compiler rejects that 'lefthand is not a variable', because it knows that the lefthand is 'a copy' that will evaporate soon.

Here:

foo.mystructList[5].flip()

compiler cannot warn you: you are calling a method on a copy. What happens, is up to the method - if it plays along with structs well, it will work. Example:

var area = foo.rectangles[5].calculatearea();   // =x*y, OK!
foo.rectangles[5].validate();  // throw when x<0 || y<0, OK!
foo.rectangles[5].draw(); // call some UI rendere with x,y,sizeX,sizeY, OK!

..but if it tries to alter the struct, it will still succeed, but on the copy. There's no warning, since it's correct in all cases - just suprising when seen for the first time.

For a fun example, consider 'chaining':

struct Rect {
    ....
    public Rect twiceMe() {
        this.SizeX *= 2;
        this.SizeY *= 2;
        return this;
    }
}

foo.rectangles[5].twiceMe().draw();

Here, twiceMe() returns altered this, so I can "immediatelly" call draw on it. It seems as if I multiplied the rectangle by two on the fly, and then drawn it on screen with twice the size, but there will be no changes in the array!

Works, but, actually, none of those calls were really immediate. The above example works like:

  • read sixth item from the array, return the item (automatic copy here)
  • call twiceMe() on that copy, return "this" from it (automatic copy here, too)
  • call draw on copy-of-enlargedcopy-of-original

To sum up: don't overuse structs, or know them well, add extra care when you are mutating them.

quetzalcoatl
  • 32,194
  • 8
  • 68
  • 107
  • 2
    To sum up: don't use mutable structs :) – nawfal Jun 29 '15 at 23:31
  • @nawfal: true :) and I just've edited all 'array' to 'list' since actually, that's very important bit. thanks for reminding, I need to be careful with words :) – quetzalcoatl Jun 29 '15 at 23:33
  • I understood that structs were value types (that's actually why I was using them, I wanted to be able to copy data easily without worrying about references) I just thought that a reference to a struct should still change the struct value. – Superdoggy Jun 29 '15 at 23:48