I've read a lot about the mutability of structs in c#. Most of the words say mutable structs are evil. I see why. But I have a case where mutable struct seems to be legal. Of course, I'm facing problems that float around struct mutability.
Say, I have a simple struct like this, in a GIS editor application:
enum CoordinateSystem : byte { .... } // coordinate system types
struct Vertex
{
float m_x; // m_ is the original value of coordinate, it needs to be kept
float m_y;
float c_x; // c_ is a cache of the result of expensive coordinate transformation
float c_y;
CoordinateSystem cachedSystem; // the current coordinate system type in c_x and c_y
public float x { get {...} set {...}} // properties are for accessing values outside of struct
public float y { get {...} set {...}} // and transforming m_x,m_y into c_x,c_y if necessary
}
Properties are for accessing the coordinates from outside. From an outer singleton class it is known to the struct what coordinate system is needed when accessing x and y properties. The get property would transform m_x and m_y on-demand if necessary and beside returning the value it stores the result in c_x and c_y for furher accesses. Of course, caching is necessary because coordinate transformation is very expensive. With caching, only the first access would be slow and all further access in the same coordinate system is "immediate".
Vertices live in a List, so basically a vertex list of length 10000 is allocated as a Vertex[10000] in the List.
Obviously, the problem is that accessing (getting out) a Vertex from the list gives back a copy of struct stored in the List<> so caching after transformation has no effect because it stores the result in the short-living copy, and not in the List<> itself.
I don't want to change Vertex to class because it would allocate (on a 64 bit runtime) 10000*8 bytes as reference in one block, and 10000 * 17 bytes in 10000 block, this would roughly + 1/3 memory and 10000 times of number of allocated blocks. (I know that it's a rough calculation because of alignment, ...) And this is about one vertex list, I have ten thousands of them so class would waste a lot of memory.
I would like to keep the transformation transparent for outer accessors because Vertex is a core type in an app referenced many times. Another reason is that only vertex knows about coordinate systems, all other parts look at Vertex.x and Vertex.y as "numbers", nothing more. This way x and y properties should do the transformation.
Question is: what the right approach for solving this problem?
(Please don't close this question as opinion-based. This is not one of that. I'm interested in answers based on facts, considering the aim of the application.)
CoordinateSystemcould be different for every single vertex. so its better to have cached values in another list and when everCoordinateSystemchanges recreate the list with new values. - M.kazem Akhgarystructs are useful only if stored/exposed from arrays, which currently are the only collection structure that allows mutating a struct element through indexer. C#7ref returnswould probably allow exposing more indexers like array, but until then... Also for backward compatibility they will probably keep theList<T>as it is now. - Ivan Stoev