I am using the XNA Framework to make a learning project. It has a Point struct w
ID: 644438 • Letter: I
Question
I am using the XNA Framework to make a learning project. It has a Point struct which exposes an X and Y value; for the purpose of optimization, it breaks the rules for proper struct design, since its a mutable struct.
As Marc Gravell, John Skeet, and Eric Lippert point out in their respective posts about GetHashCode() (which Point overrides), this is a rather bad thing, since if an object's values change while its contained in a hashmap (ie, LINQ queries), it can become "lost".
However, I am making my own Point3D struct, following the design of Point as a guideline. Thus, it too is a mutable struct which overrides GetHashCode(). The only difference is that mine exposes and int for X, Y, and Z values, but is fundamentally the same. The signatures are below:
public struct Point3D : IEquatable<Point3D>
{
public int X;
public int Y;
public int Z;
public static bool operator !=(Point3D a, Point3D b) { }
public static bool operator ==(Point3D a, Point3D b) { }
public Point3D Zero { get; }
public override int GetHashCode() { }
public override bool Equals(object obj) { }
public bool Equals(Point3D other) { }
public override string ToString() { }
}
I have tried to break my struct in the way they describe, namely by storing it in a List<Point3D>, as well as changing the value via a method using ref, but I did not encounter they behavior they warn about (maybe a pointer might allow me to break it?).
Am I being too cautious in my approach, or should I be okay to use it as is?
Explanation / Answer
Let's break it down.
Is a mutable struct with public fields a good idea?
No. You already know that it is not, but you're choosing to play with fire while walking on thin ice anyways. I would advise against using Point as a model. Value types should logically be values, and values don't change, variables change.
That said, there can be good performance reasons for doing what you're doing; I would only do so if I had clear empirical evidence that there was no other way to meet my performance goals.
If I put a mutable struct into a dictionary and then mutate it, can the struct be "lost" in the hash code?
The question is not answerable because it presumes a falsehood. You can't put a mutable struct into a dictionary and then mutate it. Asking "what happens when I do something impossible?" doesn't afford answers upon which you can make engineering decisions.
What happens when I try to mutate a mutable struct that I've put into a dictionary?
Value types are copied by value; that's why they're called "value types". When you fetch the value from the dictionary, you make a copy. If you then mutate it, you mutate the copy. If you try to mutate it directly by changing a field, the compiler will tell you that you are mutating a copy and that the mutation will be lost.
So what's the real danger of putting a mutable struct into a dictionary?
The danger of putting a mutable value type in a dictionary is that mutations are lost, not that the object gets lost in the dictionary. That is, when you say:
struct Counter
{
public int x;
public void Increment() { x = x + 1; }
...
}
...
var c = new Counter();
var d = new Dictionary<string, Counter>();
d["hello"] = c;
c.Increment();
Console.WriteLine(c.x);
Console.WriteLine(d["hello"].x);
d["hello"].Increment();
Console.WriteLine(c.x);
Console.WriteLine(d["hello"].x);
then the increment to c is preserved but not copied to the dictionary, and the increment of the dictionary's copy is lost because it is made to a copy, not to the dictionary.
This is very confusing for people, which is why you should avoid it.
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.