Why class passed by in are mutable? #1123
Replies: 12 comments
-
What is an immutable class? :) How would the compiler enforce immutability? |
Beta Was this translation helpful? Give feedback.
-
Note: structs passed to a function using 'in' are effectively immutable. That's because any mutation that might happen (for example, calling an instance method), happens on a defensive copy of that struct. This is how immutability can be achieved. As far as the caller is concerned, the value can't ever change. No such thing is possible with classes. There is no way to do a 'defensive copy' to give a copy of the value to operate on. And, if anything that could cause mutation were disallowed on classes, then you would literally be unable to use them at all (except to access fields off of them). |
Beta Was this translation helpful? Give feedback.
-
I’m talking about simple situation when we have a public property e.g Name. When struct with that property is passed to the function via in keyword there is no possibility to change this property. In situation when class is passed in the same manner - this property could be changed without problem. What do you mean saying defensive copy? I thought that in params are passed by reference? Do not have I right? |
Beta Was this translation helpful? Give feedback.
-
'in' params are passed by reference. But operations on an 'in' parameter will vary depending on the type of variable passed in. For example, if you have a normal struct, then you can call methods on it. In this case, in order to not allow the original struct to be mutated, the compiler will make a 'defensive copy' of the struct (literally an exact copy of its contents in memory), and will pass that a reference to that copy as the "this" to the method it calls. That way if the method tries to change anything, nothing will happen to the original. (Note: that's how calling methods works today when you have something like Now, if you pass a readonly struct (i.e. literally a struct declared as |
Beta Was this translation helpful? Give feedback.
-
I recommend reading this doc: https://docs.microsoft.com/en-us/dotnet/csharp/reference-semantics-with-value-types This behavior is called out here:
-- Note: defensive copies are also made when accessing things by "ref readonly" members. The compiler doesn't know (for non-readonly-structs) that the methods of that struct will not mutate, so if you call a method on a "ref readonly" returned value, a copy will be made, and the method will be called on that copy. |
Beta Was this translation helpful? Give feedback.
-
Thanks a lot for the answers. Let’s me clarifying one question. In situation when struct is normal (not marked as read only) any methods is called on the copy of this structure? In this situation I do not see any boost in compare to normal pass struct by value. This approach also do not protect against changing the state of any reference types if struct contains any. |
Beta Was this translation helpful? Give feedback.
-
Only:
I think that's the whole list. But i'm not 100% certain. It may be that a method called on a struct variable used in a dispose block is also copied. But i can't remember. Basically, in any context where you say the variable is readonly, and you have a struct, the compiler must make a copy (if it's not a "readonly-struct"). After all, if it didn't, then the value could mutate, and you wouldn't really have a readonly-variable would you? :) |
Beta Was this translation helpful? Give feedback.
-
Note: there is a lot of subtlety here that people generally gloss over when using structs (often because structs are immutable anyways, so you don't normally notice this stuff). However, its worthwhile to know if you intend to use these types as deep understanding is necessary to use them properly and to be able to squeeze the maximum perf out of them. |
Beta Was this translation helpful? Give feedback.
-
Thank you for the comments again! I was surprised that implicit changing any of properties of class passed using in keywords does not generate any error. Right now the whole topic is more clear for me |
Beta Was this translation helpful? Give feedback.
-
As I understand it, If you want your object to be immutable, write an immutable class 😀 Maybe someday, we'll get |
Beta Was this translation helpful? Give feedback.
-
Shouldn't passing a I don't understand what purpose it serves other than being a deoptimization |
Beta Was this translation helpful? Give feedback.
-
I find the benaadams suggestion correct. Perhabs passing the reference types by in should generete a compile error. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I have a question related to this feature. Why structs pass to the function using in keyword are immutable when classes are mutable? I'm asking because in my opinion this behaviour introduces unnecessary confusion. I think all types pass by in should be immutable. Could someone explain me why this works in this way right now?
Beta Was this translation helpful? Give feedback.
All reactions