Why do mutations on readonly structs not break?
structs
are value types and therefore have a value type sematics. This means each time you access the struct you basically work with a copy of the struct's value.
In your sample you don't change the original struct
but only a temporary copy of it.
See here for further explanations:
Why are mutable structs evil
In .net, a struct instance method is semantically equivalent to a static struct method with a an extra ref
parameter of the struct type. Thus, given the declarations:
struct Blah {
public int value;
public void Add(int Amount) { value += Amount; }
public static void Add(ref Blah it; int Amount; it.value += Amount;}
}
The method calls:
someBlah.Add(5);
Blah.Add(ref someBlah, 5);
are semantically equivalent, except for one difference: the latter call will only be permitted if someBlah
is a mutable storage location (variable, field, etc.) and not if it is a read-only storage location, or a temporary value (result of reading a property, etc.).
This faced the designers of .net languages with a problem: disallowing the use of any member functions on read-only structs would be annoying, but they didn't want to allow member functions to write to read-only variables. They decided to "punt", and make it so that calling an instance method on a read-only structure will make a copy of the structure, invoke the function on that, and then discard it. This has the effect of slowing down calls to instance methods which do not write the underlying struct, and making it so that an attempt to use a method which updates the underlying struct on a read-only struct will yield different broken semantics from what would be achieved if it were passed the struct directly. Note that the extra time taken by the copy will almost never yield correct semantics in cases which would not have been correct without the copy.
One of my major peeves in .net is that there is still (as of at least 4.0, and probably 4.5) still no attribute via which a struct member function can indicate whether it modifies this
. People rail about how structs should be immutable, rather than providing the tools to allow structs to safely offer mutating methods. This, despite the fact that so-called "immutable" structs are a lie. All non-trivial value types in mutable storage locations are mutable, as are all boxed value types. Making a struct "immutable" may compel one to rewrite a whole struct when one only wants to change one field, but since struct1 = struct2
mutates struct1 by copying all the public and private fields from struct2, and there's nothing the type definition for the struct can do to prevent that (except not have any fields) it does nothing to prevent unexpected mutation of struct members. Further, because of threading issues, structs are very limited in their ability to enforce any sort of invariant relationship among their fields. IMHO, it would generally be better for a struct with to allow arbitrary field access, making clear that any code receiving a struct must check whether its fields meet all required conditions, than try to prevent the formation of structs which don't meet conditions.