Is pass by reference just a legacy? - c#

Perhaps this is a bit naive of me, but I can't really seem to find/think of a decent use-case for "pass by reference". Changing an immutable string (as some other Q/As have mentioned) is generally avoidable and returning multiple variables is generally better handled by returning a Tuple, List, array, etc.
The example on MSDN is terrible in my opinion; I would simply be returning a value in the Square method, instead of having it declared as void.
It seems to me like it's a bit of a legacy part of C#, rather than an integral part of it. Can someone smarter than me try to explain why it's still around and/or some real-world use-cases that are actually practical (i.e. Changing an immutable string is avoidable in almost every case).

P.S.: I followed up on some of the comments by #KallDrexx and #newacct. I see now that they were right and I was wrong: my answer was somewhat misleading. The excellent article "Java is pass-by-value, dammit!" by Scott Stanchfield (Java-specific, but still mostly relevant to C#) finally convinced me so.
I'll leave the misleading bits of my answer striked through
for now, but might later remove them.
Pass by reference is not just used with ref or out parameters. More importantly, all reference types are passed by reference (thus their name), although this happens transparently.
Here are three frequent use cases for pass-by-reference:
Prevent copying of large structs when passing them around. Imagine you have a byte[] array representing a binary large object (BLOB), possibly a few megabytes in size value of some struct type that contains lots of fields. A value of that type might potentially occupy quite a lot of memory. Now you want to pass this value to some method. Do you really want to pass it by value, i.e. create a temporary copy?
You can avoid unnecessary copying of large structs by passing them by reference.
(Luckily for us, arrays such as byte[] are reference types, so the array's contents are already passed by refence.)
It is often suggested (e.g. in Microsoft's Framework Design Guidelines) that types having value-type semantics should be implemented as reference types if they exceed a certain size (32 bytes), so this use case should not be very frequent.
Mutability. If you want a method to be able to mutate a struct value that is passed to it, and you want the caller to observe the mutation of his version of that object, then you need pass by reference (ref). If the value is passed to the method by value, it receives a copy; mutating the copy will leave the original object unmodified.
This point is also mentioned in the Framework Design Guideline article linked to above.
Note the widespread recommendation against mutable value types (See e.g. "Why are mutable structs evil?"). You should rarely have to use ref or out parameters together with value types.
COM interop as mentioned in this answer often requires you to declare ref and out parameters.

Suppose you want to have a function that mutates a value (Notice, value, not object), and you also want that function to return some success indicator. A good practice would be to return a boolean indicating success / failure, but what about the value? So you use a ref:
bool Mutate(ref int val)
{
if(val > 0)
{
val = val * 2;
return true;
}
return false;
}

It's true that in C# there are usually alternatives to ref and out - for example, if you want to return more than one value to the caller, you could return a tuple, or a custom type, or receive a reference type as a parameter and change multiple values inside it.
However, these keywords can still be a convenient solution in situations like interop:
// C
int DoSomething(int input, int *output);
// C#
[DllImport(...)]
static extern int DoSomething(int input, ref int output);

There are indeed only few cases where explicit ref parameters are useful from a functional point of view.
One example I have seen:
public static void Swap<T>(ref T a, ref T b)
{
var temp = a;
a = b;
b = temp;
}
Such a method is useful in some sort algorithms, for example.
One reason why ref parameters are sometimes used, is as an optimization technique. A large struct (value type) is sometimes passed by ref, even if the called method has no intent to modify the struct's value, to avoid copying the structs contents. You could argue that a large struct would better be a class (i.e. a reference type), but that has disadvantages when you keep large arrays of such objects around (for example in graphics processing). Being an optimization, such a technique does not improve code readability, but improves performance in some situations.
A similar question could be asked about pointers. C# has support for pointers, through the unsafe and fixed keywords. They are hardly ever needed from a functional point of view: I can't really think of a function that could not be coded without the use of pointers. But pointers are not used to make the language more expressive or the code more readable, they are used as a low level optimization technique.
In fact, passing a struct by reference really is a safe way to pass a pointer to the struct's data, a typical low level optimization technique for large structs.
Is a feature that enables low level optimizations a legacy feature? That may depend on your point of view, but you aren't the only C# user. Many of them will tell you that the availability of pointers and other low level constructs is one of the big advantages C# has over some other languages. I for one don't think that ref parameters are a legacy feature, they are an integral part of the language, useful in some scenarios.
That does not mean that you have to use ref parameters, just like you don't have to use LINQ, async/await or any other language feature. Just be happy it's there for when you do need it.

Related

Use of ref and this to change a variable value

I came across ref and this parameter keywords lately, and I can't find any good comparison performance wise.
void main()
{
int original = 1;
/* Which one is best? */
original = DoMaths(original, 2);
DoMaths(ref original, 2);
original = original.DoMaths(2);
}
int DoMaths(int original, int arg)
{
return original * arg;
}
void DoMaths(ref int original, int arg)
{
original *= arg;
}
int DoMaths(this int original, int arg)
{
return original * arg;
}
I came across ref and this parameter keywords lately, and I can't find any good comparison performance wise
You found no good comparison because no meaningful comparison is possible.
The this keyword, as used in your code example, has literally no effect on runtime performance. It is strictly a marker signaling to the compiler that the method being declared is an extension method. The code you posted won't even compile (extension methods are required to be static, and they are legal only in a class that is also static), but when they are declared and used correctly, they affect only the compile-time semantics of the code, allowing you to write the call to the method as if it was an instance method called using the first parameter (marked with this).
Otherwise, it's exactly like calling any other static method, and has the exact same performance characteristics. And comparing performance between a static method and one using a by-reference parameter (which via ref or out) is also meaningless. The two are not even mutually exclusive.
Even if you were to conceive of a question comparing the use of ref to some other otherwise-comparable scenario, it is generally impossible for anyone else to answer the question in a useful way, especially without a good, minimal, complete code example that clearly illustrates the question. Even with such an example, a useful answer is unlikely because such a code example is necessarily divorced from the real-world context in which the actual performance is presumably a concern. I.e. any answer would be primarily of academic value.
In a forum like this, the best and only reasonable answer to a question that takes the form of "which of these performs better?" is "which performed better when you tested it in your real-world scenario?"
Finally, note that passing by-reference significantly changes the semantics of the method. As such, even where performance is a concern and even if it actually happens that passing by-reference improves performance, one should be extremely wary of using ref solely as a performance-enhancement measure. It is extremely unusual for a single method call to be a significant performance bottleneck, and even less likely that passing by-reference could produce a significant enough difference in performance as compared to a semantically-correct implementation to justify harming the expressiveness of the code in that way.

Why are System.Windows.Point & System.Windows.Vector mutable?

Given that mutable structs are generally regarded as evil (e.g., Why are mutable structs “evil”?), are there potential benefits that might have prompted the designers of the .NET framework to make System.Windows.Point & System.Windows.Vector mutable?
I'd like to understand this so I can decide whether it would make sense to make my own similar structs mutable (if ever). It's possible the decision to make Point and Vector mutable was just an error in judgment, but if there was a good reason (e.g., a performance benefit), I'd like to understand what it was.
I know that I've stumbled over the implementation of the Vector.Normalize() method a few times because it, surprise (!), does not return a fresh Vector. It just alters the current vector.
I always think it should work like this:
var vector = new Vector(7, 11);
var normalizedVector = vector.Normalize(); // Bzzz! Won't compile
But it actually works like this:
var vector = new Vector(7, 11);
vector.Normalize(); // This compiles, but now I've overwritten my original vector
...so, it seems like immutability is a good idea simply for avoiding confusion, but again, perhaps it's worth that potential confusion in some cases.
These types are in the System.Windows namespace and are generally used in WPF applications. The XAML markup of an application is a big part of the framework so for a lot of things, they need a way to be expressed using XAML. Unfortunately there's no way to invoke non-parameterless constructors using WPF XAML (but it is possible in loose XAML) so trying to call a constructor with the appropriate arguments to initialize it wouldn't be possible. You can only set the values of the object's properties so naturally, these properties needed to be mutable.
Is this a bad thing? For these types, I'd say no. They are just for holding data, nothing more. If you wanted to get the size a Window wanted to be, you'd access the DesiredSize to get the Size object representing the size it wanted. You're not meant to "change the desired size" by altering the Width or Height properties of the Size object you get, you change the size by providing a new Size object. Looking at it this way is a lot more natural I believe.
If these objects were more complex and did more complicated operations or had state, then yes, you wouldn't want to make these types neither mutable nor structs. However since they're just about as simple and basic as it can get (essentially a POD), structs would be appropriate here.
Such types are mutable because, contrary to what some people might claim, mutable value-type semantics are useful. There are a few places where .net tries to pretend that value types should have the same semantics as reference types. Since mutable value-type semantics are fundamentally different from mutable reference-type semantics, pretending they're the same will cause problems. That doesn't make them "evil", however--it merely shows a flaw in an object model which assumes that acting upon a copy of something will be semantically equivalent to acting upon the original. True if the thing in question is an object reference; generally true--but with exceptions--if it's an immutable structure; false if it's a mutable structure.
One of the beautiful things about structs with exposed fields is that their semantics are readily ascertained by even simple inspection. If one has a Point[100] PointArray, one has 100 distinct instances of Point. If one says PointArray[4].X = 9;, that will change one item of PointArray and no other.
Suppose instead of using struct Point, one had a mutable class PointClass:
class PointClass {public int X; public int Y;};
How many PointClass instances are stored in PointClass[100] PointClassArray? Is there any way to tell? Will the statement PointClass[4].X = 9 affect the value of PointClass[2].X? What about someOtherObject.somePoint.X?
While the .net collections are not well suited to storage of mutable structs, I would nonetheless regard:
Dictionary<string, Point>;
...
Point temp = myDict["George"];
temp.X = 9;
myDict["George"] = temp;
to have relatively clear semantics, at least in the absence of threading issues. While I consider it unfortunate that .net collections don't provide a means by which one could simply say myDict[lookupKey].X = 9; I would still regard the above code as pretty clear and self-explanatory without having to know anything about Point other than the fact that it has a public integer field called X. By contrast, if one had a Dictionary<PointClass>, it would be unclear what one should be expected to do to change the X value associated with "George". Perhaps the PointClass instance associated with George is not used anywhere else, in which case one may simply write the appropriate field. On the other hand, it's also possible that someone else has grabbed a copy of MyDict["George"] for the purpose of capturing the values therein, and isn't expecting that the PointClass object he's grabbed might change.
Some people might think "Point" should be an immutable struct, but the effect of a statement like somePoint.X = 5; can be fully determined knowing only that somePoint is a variable of type Point, which in turn is a struct with a public int field called X. If Point were an immutable struct, one would have to instead say something like somePoint = new Point(5, somePoint.Y);, which would, in addition to being slower, require examining the struct to determine that all of its fields are initialized in the constructor, with X being the first and Y the second. In what sense would that be an improvement over somePoint.X = 5;?
BTW, the biggest 'gotcha' with mutable structs stems from the fact that there's no way for the system to distinguish struct methods which alter 'this' from those which do not. A major shame. The preferred workarounds are either to use functions which return new structs derived from old ones, or else use static functions which accept "ref" struct parameters.
Possibilities:
It seemed like a good idea at the time to someone who didn't consider the use-cases where it would bite people. List<T>.Enumerator is a mutable struct that was used because it seemed like a good idea at the time to take advantage of the micro-opts that would often happen. It's almost the poster-child for mutable structs being "evil" as it's bitten more than a few people. Still, it seemed like a good idea to someone at the time...
They did think of the downsides, but had some use-case known to them where the performance differences went in struct's favour (they don't always) and was considered important.
They didn't consider structs evil. "Evil" is an opinion about down-sides beating up-sides, not a demonstrable fact, and not everyone has to agree with something even if Eric Lippert and Jon Skeet say it. Personally I think they're not evil, they're just misunderstood; but then again, evil is often easier to deal with than misunderstood for a programmer, so that's actually worse... ;) Maybe those involved disagree.

Why is it okay that this struct is mutable? When are mutable structs acceptable?

Eric Lippert told me I should "try to always make value types immutable", so I figured I should try to always make value types immutable.
But, I just found this internal mutable struct, System.Web.Util.SimpleBitVector32, in the System.Web assembly, which makes me think that there must be a good reason for having a mutable struct. I'm guessing the reason that they did it this way is because it performed better under testing, and they kept it internal to discourage its misuse. However, that's speculation.
I've C&P'd the source of this struct. What is it that justifies the design decision to use a mutable struct? In general, what sort of benefits can be gained by the approach and when are these benefits significant enough to justify the potential detriments?
[Serializable, StructLayout(LayoutKind.Sequential)]
internal struct SimpleBitVector32
{
private int data;
internal SimpleBitVector32(int data)
{
this.data = data;
}
internal int IntegerValue
{
get { return this.data; }
set { this.data = value; }
}
internal bool this[int bit]
{
get {
return ((this.data & bit) == bit);
}
set {
int data = this.data;
if (value) this.data = data | bit;
else this.data = data & ~bit;
}
}
internal int this[int mask, int offset]
{
get { return ((this.data & mask) >> offset); }
set { this.data = (this.data & ~mask) | (value << offset); }
}
internal void Set(int bit)
{
this.data |= bit;
}
internal void Clear(int bit)
{
this.data &= ~bit;
}
}
Given that the payload is a 32-bit integer, I'd say this could easily have been written as an immutable struct, probably with no impact on performance. Whether you're calling a mutator method that changes the value of a 32-bit field, or replacing a 32-bit struct with a new 32-bit struct, you're still doing the exact same memory operations.
Probably somebody wanted something that acted kind of like an array (while really just being bits in a 32-bit integer), so they decided they wanted to use indexer syntax with it, instead of a less-obvious .WithTheseBitsChanged() method that returns a new struct. Since it wasn't going to be used directly by anyone outside MS's web team, and probably not by very many people even within the web team, I imagine they had quite a bit more leeway in design decisions than the people building the public APIs.
So, no, probably not that way for performance -- it was probably just some programmer's personal preference in coding style, and there was never any compelling reason to change it.
If you're looking for design guidelines, I wouldn't spend too much time looking at code that hasn't been polished for public consumption.
Actually, if you search for all classes containing BitVector in the .NET framework, you'll find a bunch of these beasts :-)
System.Collections.Specialized.BitVector32 (the sole public one...)
System.Web.Util.SafeBitVector32 (thread safe)
System.Web.Util.SimpleBitVector32
System.Runtime.Caching.SafeBitVector32 (thread safe)
System.Configuration.SafeBitVector32 (thread safe)
System.Configuration.SimpleBitVector32
And if you look here were resides the SSCLI (Microsoft Shared Source CLI, aka ROTOR) source of System.Configuration.SimpleBitVector32, you'll find this comment:
//
// This is a cut down copy of System.Collections.Specialized.BitVector32. The
// reason this is here is because it is used rather intensively by Control and
// WebControl. As a result, being able to inline this operations results in a
// measurable performance gain, at the expense of some maintainability.
//
[Serializable()]
internal struct SimpleBitVector32
I believe this says it all. I think the System.Web.Util one is more elaborate but built on the same grounds.
SimpleBitVector32 is mutable, I suspect, for the same reasons that BitVector32 is mutable. In my opinion, the immutable guideline is just that, a guideline; however, one should have a really good reason for doing so.
Consider, also, the Dictionary<TKey, TValue> - I go into some extended details here. The dictionary's Entry struct is mutable - you can change TValue at any time. But, Entry logically represents a value.
Mutability must make sense. I agree with the #JoeWhite: somebody wanted something that acted kind of like an array (while really just being bits in a 32-bit integer); also that both BitVector structs could easily have been ... immutable.
But, as a blanket statement, I disagree with it was probably just some programmer's personal preference in coding style and lean more toward there was never [nor is there] any compelling reason to change it. Simply know and understand the responsibility of using a mutable struct.
Edit
For the record, I do heartily agree that you should always try to make a struct immutable. If you find that requirements dictate member mutability, revisit the design decision and get peers involved.
Update
I was not initially confident in my assessment of performance when considering a mutable value type v. immutable. However, as #David points out, Eric Lippert writes this:
There are times when you need to wring every last bit of performance
out of a system. And in those scenarios, you sometimes have to make a
tradeoff between code that is clean, pure, robust ,
understandable, predictable, modifiable and code that is none of the
above but blazingly fast.
I bolded pure because a mutable struct does not fit the pure ideal that a struct should be immutable. There are side-affect of writing a mutable struct: understability and predictability are compromised, as Eric goes on to explain:
Mutable value types ... behave
in a manner that many people find deeply counterintuitive, and thereby
make it easy to write buggy code (or correct code that is easily
turned into buggy code by accident.) But yes, they are real fast.
The point Eric is making is that you, as the designer and/or developer need to make a conscious and informed decision. How do you become informed? Eric explains that also:
I would consider coding up two benchmark solutions -- one using
mutable structs, one using immutable structs -- and run some
realistic user-scenario-focused benchmarks. But here's the thing: do not pick the faster one. Instead, decide BEFORE you run the benchmark
how slow is unacceptably slow.
We know that altering a value type is faster than creating a new value type; but considering correctness:
If both solutions are acceptable, choose the one that is clean,
correct and fast enough.
The key is being fast enough to offset side affects of choosing mutable over immutable. Only you can determine that.
Using a struct for a 32- or 64-bit vector as shown here is reasonable, with a few caveats:
I would recommend using an Interlocked.CompareExchange loop when performing any updates to the structure, rather than just using the ordinary Boolean operators directly. If one thread tries to write bit 3 while another tries to write bit 8, neither operation should interfere with the other beyond delaying it a little bit. Use of an Interlocked.CompareExchange loop will avoid the possibility of errant behavior (thread 1 reads value, thread 2 reads old value, thread 1 writes new value, thread 2 writes value computed based on old value and undoes thread 1's change) without needing any other type of locking.
Structure members, other than property setters, which modify "this" should be avoided. It's better to use a static method which accepts the structure as a reference parameter. Invoking a structure member which modifies "this" is generally identical to calling a static method which accepts the member as a reference parameter, both from a semantic and performance standpoint, but there's one key difference: If one tries to pass a read-only structure by reference to a static method, one will get a compiler error. By contrast, if one invokes on a read-only structure a method which modifies "this", there won't be any compiler error but the intended modification won't happen. Since even mutable structures can get treated as read-only in certain contexts, it's far better to get a compiler error when this happens than to have code which will compile but won't work.
Eric Lippert likes to rail on about how mutable structures are evil, but it's important to recognize his relation to them: he's one of the people on the C# team who is charged with making the language support features like closures and iterators. Because of some design decisions early in the creation of .net, properly supporting value-type semantics is difficult in some contexts; his job would be a lot easier if there weren't any mutable value types. I don't begrudge Eric for his point of view, but it's important to note that some principles which may be important in framework and language design are not so applicable to application design.
If I understand correctly, you cannot make a serializable immutable struct simply by using SerializableAttribute. This is because during deserialization, the serializer instantiates a default instance of the struct, then sets all the fields following instantiation. If they are readonly, deserialization will fail.
Thus, the struct had to be mutable, else a complex serialization system would have been necessary.

C# why need struct if class can cover it?

Just wondering why we need struct if class can do all struct can and more? put value types in class has no side effect, I think.
EDIT: cannot see any strong reasons to use struct
A struct is similar to a class, with the following key differences:
A struct is a value type, whereas a
class is a reference type.
A struct does not support inheritance
(other than implicitly deriving from
object).
A struct can have all the members a
class can, except the following:
A parameterless constructor
A finalizer
Virtual members
A struct is used instead of a class when value type semantics are desirable. Good examples of structs are numeric types, where it is more natural for assignment to copy a value rather than a reference. Because a struct is a value type, each instance does not require instantiation of an object on the heap. This can be important when creating many instances of a type.
Custom value types aren't absolutely necessary - Java does without them, for example. However, they can still be useful.
For example, in Noda Time we're using them pretty extensively, as an efficient way of representing things like instants without the overhead of an object being involved.
I wouldn't say that "class can do all struct can and more" - they behave differently, and should be thought of differently.
Why use a struct when a class works? Because sometimes a class doesn't work.
In addition to the performance reasons mentioned by Reed Copsey (short version: fewer objects that the GC needs to track, allowing the GC to do a better job), there is one place where structures must be used: P/Invoke to functions that require by-value structures or structure members.
For example, suppose you wanted to invoke the CreateProcess() function. Further suppose that you wanted to use a STARTUPINFOEX structure for the lpStartupInfo parameter to CreateProcess().
Well, what's STARTUPINFOEX? This:
typedef struct _STARTUPINFOEX {
STARTUPINFO StartupInfo;
PPROC_THREAD_ATTRIBUTE_LIST lpAttributeList;
} STARTUPINFOEX, *LPSTARTUPINFOEX;
Notice that STARTUPINFOEX contains STARTUPINFO as its first member. STARTUPINFO is a structure.
Since classes are reference types, if we declared the corresponding C# type thus:
[StructLayout(LayoutKind.Sequential)]
class STARTUPINFO { /* ... */ }
class STARTUPINFOEX { public STARTUPINFO StartupInfo; /* ... */ }
The corresponding in-memory layout would be wrong, as STARTUPINFOEX.StartupInfo would be a pointer (4 bytes on ILP32 platforms), NOT a structure (as is required, 68 bytes in size on ILP32 platforms).
So, to support invoking arbitrary functions which accept arbitrary structures (which is what P/Invoke is all about), one of two things are necessary:
Fully support value types. This allows C# to declare a value type for STARTUPINFO which will have the correct in-memory layout for marshaling (i.e. struct support, as C# has).
Some alternate syntax within P/Invokeable structures which would inform the runtime marshaler that this member should be laid out as a value type instead of as a pointer.
(2) is a workable solution (and may have been used in J/Direct in Visual J++; I don't remember), but given that proper value types are more flexible, enable a number of performance optimizations not otherwise achievable, and make sensible use within P/Invoke scenarios, it's no surprise that C# supports value types.
In general, use a class.
Only use a struct when you absolutely need value type semantics.
Structs are also often required for performance reasons. Arrays of structs take quite a bit less memory, and get much better cache coherency than an array of object references. This is very important if you're working with something like a rendering system, and need to generate 5 million vertices, for example.
For details, see Rico Mariani's Performance Quiz + Answers.
Structs are useful simply because they are passed by value, which can actually be useful in certain algorithms. This is actually something that classes CAN'T do.
struct ArrayPointer<T>
{
public T[] Array;
public int Offset;
}
You can pass this structure to a method and the method can alter the value of Offset for its own needs. Meanwhile, once you return from the method, it will behave as if Offset never changed.
Struct Vs Class in C#
C# Struct usage tips?
Why do we need struct? (C#)
For the average application developer, using classes is the norm. On the surface, classes make structs seem unnecessary, but when you dig deeper into the nitty-gritty details they are actually quite different.
See here for some differences between structs and classes.
The most well-known difference is that classes are reference-types and structs are value-types. This is important because it allows a library developer to control how instances of a data-type can be used.
1, performance. In some cases using structures we'll get much better performance.
2, data immutability. By changing some property of a struct you'll get a new struct. This is very useful in some cases
3, better control of in memory representation. We can exactly define how the struct is located in memory and this allows us to serialize and deserialize some binary data fast and efficiently.
It is almost a must to use for interop with underlying data structure used by win32 API. I suppose a very big reason to have it in .net could be due to that reason.

Immutability of structs [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why are mutable structs evil?
I read it in lots of places including here that it's better to make structs as immutable.
What's the reason behind this? I see lots of Microsoft-created structs that are mutable, like the ones in xna. Probably there are many more in the BCL.
What are the pros and cons of not following this guideline?
Structs should represent values. Values do not change. The number 12 is eternal.
However, consider:
Foo foo = new Foo(); // a mutable struct
foo.Bar = 27;
Foo foo2 = foo;
foo2.Bar = 55;
Now foo.Bar and foo2.Bar is different, which is often unexpected. Especially in the scenarios like properties (fortunately the compiler detect this). But also collections etc; how do you ever mutate them sensibly?
Data loss is far too easy with mutable structs.
The big con is that things don't behave how you expect them to - particularly if the mutability comes from a mixture of the direct value and a reference type within it.
To be honest, I can't remember off the top of my head all the weird problems I've seen people come up with in newsgroups when they've used mutable structs - but those reasons certainly exist. Mutable structs cause problems. Stay away.
EDIT: I've just found an email I wrote a while ago on this topic. It elaborates just a little bit:
It's philosophically wrong: a struct should represent some sort of fundamental value. Those are basically immutable. You don't get to change the number 5. You can change a variable's value from 5 to 6, but you don't logically make a change to the value itself.
It's practically a problem: it creates lots of weird situations. It's particularly bad if it's mutable via an interface. Then you can start changing boxed values. Ick. I've seen a lot of newsgroup posts which are due to people trying to use mutable structs and running into issues. I saw a very strange LINQ example which was failing because List<T>.Enumerator is a struct, for example.
I use mutable structs often in my (performance critical) project - and I don't run into problems, because I understand the implications of copy semantics. As far as I can tell, the main reason people advocate immutable structs is so that people who don't understand the implications can't get themselves in trouble.
That's not such a terrible thing - but we're in danger now of it becoming "the gospel truth", when in fact there are times where it is legitimately the best option to make a struct mutable. Like with all things, there are exceptions to the rule.
There is nothing cheaper to manipulate than a mutable struct, which is why you often see it in high performance code like the graphics processing routines.
Unfortunately mutable structs don't play well with objects and properties, it is way too easy to modify a copy of a stuct instead of the struct itself. Thus they aren't appropriate for most of your code.
P.S. To avoid the cost of copying mutable structs, they are usually stored and passed in arrays.
The technical reason is that mutable structs appear to be able to do things that they don't actually do. Since the design-time semantics are the same as reference types, this becomes confusing for developers. This code:
public void DoSomething(MySomething something)
{
something.Property = 10;
}
Behaves quite differently depending on if MySomething is a struct or a class. To me, this is a compelling, but not the most compelling reason. If you look at DDD's Value Object, you can see the connection to how structs should be treated. A value object in DDD can be best represented as a value type in .Net (and therefore a struct). Because it has no identity, it can't change.
Think of this in terms of something like your address. You can "change" your address, but the address itself hasn't changed. In fact, you have a new address assigned to you. Conceptually, this works, because if you actually changed your address, your roommates would have to move too.
You have asked for the pros and cons of not following the guideline that structs should be immutable.
Cons: The cons are well covered in existing answers, and most problems described are due to the same cause - unexpected behaviour due to structs' value semantics.
Pros: The main pro of using mutable structs can be performance. Obviously, this advice comes with all the usual caveats about optimisations: make sure that part of your code needs to be optimised and make sure any changes do actually optimise your code's performance via profiling.
For an excellent article discussing when you might want to use mutable structs, see Rico Mariani's Performance Quiz on Value-Based Programming (or more specifically, the answers).
A struct should generally represent a single unity of some kind. As such it doesn't make much sense to change one of the properties of the value, it makes more sense to create a completely new value if you want a value that is different somehow.
The semantics gets simpler when using immutable structs, and you avoid pitfalls like this:
// a struct
struct Interval {
int From { get; set; }
int To { get; set; }
}
// create a list of structs
List<Interval> intervals = new List<Interval>();
// add a struct to the list
intervals.Add(new Interval());
// try to set the values of the struct
intervals[0].From = 10;
intervals[0].To = 20;
The result is that the struct in the list is not changed at all. The expression Interval[0] copies the value of the struct from the list, then you change the property of the temporary value, but the value is never put back in the list.
Edit: Changed the example to use a list instead of an array.
When you copy structs around you copy their contents, so if you modify a copied version the "original" will not be updated.
This is a source for errors, since even if you know that you fall into the trap of copying a struct (just by passing it to a method) and modifying the copy.
Just happened to me again last week, kept me an hour searching for a bug.
Keeping structs immutable prevents that ...
Other than that you need to make sure you have a really good reason to use structs in the first place - "optimization" or "I want something that allocates quickly on the stack" does not count as an answer. Marshaling or things where you depend on layout - ok, but you should not typically keep those structs around for very long, they are values not objects.
the reason you should make structs immutable is that they're ValueTypes, meaning that they are copied every time you pass them to a method.
So if, for example, you had a property that returned a struct, modifying the value of a field on that struct would be worthless, because the getter would return a copy of the struct, rather than a reference to the struct. I've seen this done in code, and it's often difficult to catch.
If you design your structs for immutability, you help the programmer avoid these mistakes.

Categories