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.
Related
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.
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.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
When to use struct in C#?
Hi, I am creating an application that has a class in C# that is purely for holding variables, it does nothing else but set and get these variables. I was wondering, for efficiency and good coding practice, if I should convert this class to a struct so that it is being used properly. I've never used structs before but have been looking into them however I am having some trouble getting it working. Any advice would be appreciated!
Thanks,
Stuart
If the collection of values model a value type (that is, something that doesn't have an identity of its own and two instances with the same values are considered the same) use a struct.
Otherwise, use a class.
Using structures in place of classes depends on the scenario on which you are working. Although you can use structures in place of classes but structures lacks the ability to implement access identifiers (such as Private, Public, Protected). If you are using classes just for holding variables, you can use structures as well, but if your class contains some private, protected or public methods or variables/properties, you can not use structures.
Hope this helps!
The decision for struct or class should be based on "do I want reference type semantics or values type semantics?"
When you use a struct as parameter, the complete contents are copied. For a class just the reference is copied. So a "big struct" could have a performance penalty!
In most cases, a class is preferred. Structs are passed by value, have no inheritance, etc. You mention efficiency, is this class likely to be a performance bottleneck ?
If you make a struct though, make sure to make it immutable
I'm not sure that using a struct or not relates to good coding practise, but there are some performance benefits to using structs under certain circumstances. For example, MSDN suggests that a type which is under 16 bytes in size might be more efficiently handled by a struct than a class.
It's important to understand why a struct might be a better choice and how their memory is managed by the runtime. Libraries which must perform quickly with the minimum of overhead would consider using structs (such as a lot of the Math types in the XNA framework). There are also design issues like the fact that your struct always has a default constructor; if you want to make sure that your type can only be constructed with specific values then a struct isn't the best choice.
The long and short of it is, unless you have a very specific reason to be using structs over classes, just stick with classes.
If you want to press ahead with structs, what issues are you having with them?
It really depends on what you're trying to achieve. The fact that you currently have only getters and setters doesn't mean anything. For example, a type might be modelling the application settings read from a file. At some point you might wish to add a IsValid() or Normalize() methods. So in this case, you'd rather go with a class then a struct.
A struct should be used, when the type's identity is decided by the value of the fields. A good example from the .NET framework is Point, which has X and Y.
The second thing is that structs should be cheap to pass to and from functions:
public bool IsInRange(Point point)
{
// ...
}
Remember that point will be copied field by field here, so that should be fairly cheap.
You use structs when:
Logically represents a single value
Has an instance size less than 16
bytes
Will not be changed after creation
Will not be cast to a reference type
Refere to MCTS 70-536
I was just curious to know why structs, strings etc are immutable? What is the reason for making them immutable and rest of the objects as mutable. What are the things that are considered to make an object immutable?
Is there any difference on the way how memory is allocated and deallocated for mutable and immutable objects?
If this subject interests you, I have a number of articles about immutable programming at https://ericlippert.com/2011/05/26/atomicity-volatility-and-immutability-are-different-part-one/
I was just curious to know why structs, strings etc are immutable?
Structs and classes are not immutable by default, though it is a best practice to make structs immutable. I like immutable classes too.
Strings are immutable.
What is the reason for making them immutable and rest of the objects as mutable.
Reasons to make all types immutable:
It is easier to reason about objects that do not change. If I have a queue with three items in it, I know it is not empty now, it was not empty five minutes ago, it will not be empty in the future. It's immutable! Once I know a fact about it, I can use that fact forever. Facts about immutable objects do not go stale.
A special case of the first point: immutable objects are much easier to make threadsafe. Most thread safety problems are due to writes on one thread and reads on another; immutable objects don't have writes.
Immutable objects can be taken apart and re-used. For example, if you have an immutable binary tree then you can use its left and right subtrees as subtrees of a different tree without worrying about it. In a mutable structure you typically end up making copies of data to re-use it because you don't want changes to one logical object affecting another. This can save lots of time and memory.
Reasons to make structs immutable
There are lots of reasons to make structs immutable. Here's just one.
Structs are copied by value, not by reference. It is easy to accidentally treat a struct as being copied by reference. For example:
void M()
{
S s = whatever;
... lots of code ...
s.Mutate();
... lots more code ...
Console.WriteLine(s.Foo);
...
}
Now you want to refactor some of that code into a helper method:
void Helper(S s)
{
... lots of code ...
s.Mutate();
... lots more code ...
}
WRONG! That should be (ref S s) -- if you don't do that then the mutation will happen on a copy of s. If you don't allow mutations in the first place then all these sorts of problems go away.
Reasons to make strings immutable
Remember my first point about facts about immutable structures staying facts?
Suppose string were mutable:
public static File OpenFile(string filename)
{
if (!HasPermission(filename)) throw new SecurityException();
return InternalOpenFile(filename);
}
What if the hostile caller mutates filename after the security check and before the file is opened? The code just opened a file that they might not have permission to!
Again, mutable data is hard to reason about. You want the fact "this caller is authorized to see the file described by this string" to be true forever, not until a mutation happens. With mutable strings, to write secure code we'd constantly have to be making copies of data that we know do not change.
What are the things that are considered to make an object immutable?
Does the type logically represent something that is an "eternal" value? The number 12 is the number 12; it doesn't change. Integers should be immutable. The point (10, 30) is the point (10, 30); it doesn't change. Points should be immutable. The string "abc" is the string "abc"; it doesn't change. Strings should be immutable. The list (10, 20, 30) doesn't change. And so on.
Sometimes the type represents things that do change. Mary Smith's last name is Smith, but tomorrow she might be Mary Jones. Or Miss Smith today might be Doctor Smith tomorrow. The alien has fifty health points now but has ten after being hit by the laser beam. Some things are best represented as mutations.
Is there any difference on the way how memory is allocated and deallocated for mutable and immutable objects?
Not as such. As I mentioned before though, one of the nice things about immutable values is that something you can re-use parts of them without making copies. So in that sense, memory allocation can be very different.
Structs are not necessarily immutable, but mutable structs are evil.
Creating mutable structs can lead to all kinds of strange behavior in your application and, therefore, they are considered a very bad idea (stemming from the fact that they look like a reference type but are actually a value type and will be copied whenever you pass them around).
Strings, on the other hand, are immutable. This makes them inherently thread-safe as well as allowing for optimizations via string interning. If you need to construct a complicated string on the fly, you can use StringBuilder.
The concepts of mutability and immutability have different meanings when applied to structs and classes. A key aspect (oftentimes, the key weakness) of mutable classes is if Foo has a field Bar of type List<Integer>, which holds a reference to a list containing (1,2,3), other code which has a reference to that same list could modify it, such that Bar holds a reference to a list containing (4,5,6), even if that other code has no access whatsoever to Bar. By contrast, if Foo had a field Biz of type System.Drawing.Point, the only way anything could modify any aspect of Biz would be to have write access to that field.
The fields (public and private) of a struct can be mutated by any code which can mutate the storage location in which the struct is stored, and cannot be mutated by any code which cannot mutate the storage location where it is stored. If all of the information encapsulated within a struct is held in its fields, such a struct can effectively combine the control of an immutable type with the convenience of a mutable type, unless the struct is coded in such a way as to remove such convenience (a habit which, unfortunately, some Microsoft programmers recommend).
The "problem" with structs is that when a method (including a property implementation) is invoked on a struct in a read-only context (or immutable location), the system copies the struct, performs the method on the temporary copy, and silently discards the result. This behavior has led programmers to put forth the unfortunate notion that the way to avoid problems with mutating methods is to have many structs disallow piecewise updates, when the problems could have been better avoided by simply replacing properties with exposed fields.
Incidentally, some people complain that when a class property returns a conveniently-mutable struct, changes to the struct don't affect the class from which it came. I would posit that's a good thing--the fact that the returned item is a struct makes the behavior clear (especially if it's an exposed-field struct). Compare a snippet using a hypothetical struct and property on Drawing.Matrix with one using an actual property on that class as implemented by Microsoft:
// Hypothetical struct
public struct {
public float xx,xy,yx,yy,dx,dy;
} Transform2d;
// Hypothetical property of "System.Drawing.Drawing2d.Matrix"
public Transform2d Transform {get;}
// Actual property of "System.Drawing.Drawing2d.Matrix"
public float[] Elements { get; }
// Code using hypothetical struct
Transform2d myTransform = myMatrix.Transform;
myTransform.dx += 20;
... other code using myTransform
// Code using actual Microsoft property
float[] myArray = myMatrix.Elements;
myArray[4] += 20;
... other code using myArray
Looking at the actual Microsoft property, is there any way to tell whether the write to myArray[4] will affect myMatrix? Even looking at the page http://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.matrix.elements.aspx is there any way to tell? If the property had been written using the struct-based equivalent, there would be no confusion; the property that returns the struct would return nothing more nor less than the present value of six numbers. Changing myTransform.dx would be nothing more nor less than a write to a floating-point variable which was unattached to anything else. Anyone who doesn't like the fact that changing myTransform.dx doesn't affect myMatrix should be equally annoyed that writing myArray[4] doesn't affect myMatrix either, except that the independence of myMatrix and myTransform is apparent, while the independence of myMatrix and myArray is not.
A struct type is not immutable. Yes, strings are. Making your own type immutable is easy, simply don't provide a default constructor, make all fields private and define no methods or properties that change a field value. Have a method that should mutate the object return a new object instead. There is a memory management angle, you tend to create a lot of copies and garbage.
Structs can be mutable, but it's a bad idea because they have copy-semantics. If you make a change to a struct, you might actually be modifying a copy. Keeping track of exactly what has been changed is very tricky.
Mutable structs breed mistakes.
I like using structs a lot.
So after reading this article, are there any other concerns I should have against using them all the time?
See Also:
When should I use a struct instead of a class?
When to use struct in C#?
You should make the following considerations about structs:
structs should be immutable (mutable structs are not intuitive and unpredictable)
structs always have a default (public parameterless) constructor that cannot be changed
struct size should not exceed 16 bytes
the Equals and GetHashCode methods should be overriden for better performance
implementing the IEquatable<T> interface is recommended
redefining and == and the != operators is also recommended
I almost never define custom structs. There just aren't that many natural value types around, IMO.
In particular, I would think very, very carefully before defining a mutable struct, especially if it mutates via an interface implementation. Mutable structs behave in ways which people don't expect at all, leading to code which is hard to understand.
I think it's worth reading "Choosing Between Classes and Structures" from "Design Guidelines For Developing Class Libraries".
In particular:
Do not define a structure unless the
type has all of the following
characteristics:
It logically represents a single
value, similar to primitive types
(integer, double, and so on).
It has an instance size smaller than
16 bytes.
It is immutable.
It will not have to be boxed frequently.
Do you really develop types with all of those characteristics frequently?
They don't fit into an Object Oriented programming paradigm like classes do. They are good for small data structures, but I use classes for anything beyond that.
I think main purpose of a struct - to keep only variable types. If you keep some classes into struct - you're wrong.
Ask yourself the following questions about the set of data you're modeling with a struct:
Might it ever need to have any
get/set logic?
Might it ever need to store ANY logic
that is endemic to the data?
Might it need to inherit another set
of data?
Might another set of data need to
inherit this one?
I think if you can heartily answer "no" to all these questions, then there's no good reason not to use a struct. I think people use static subclasses in certain situations where a struct would be more than good enough.
A class is a lot simpler to implement correctly than a struct. If you implement a struct incorrectly it can give you some unexpected errors.
A struct should not be larger than 16 bytes, or you lose most of the performance benefits.
A struct is intended to be a value type, representing a single entity of some kind.
A struct should be immutable. That means that you never change one of the properties in a struct. If you want a struct value that is different you create a new value.
Use of structs should be limited to when all you really need is a small data structure. (as you read). I would only really use them for the smallest of datastructures like coordinates, offsets, and sometimes for graphics.
In many ways, you can think of structs in C# as being like scaled - down classes. They are basically the same as classes but designed more for cases where you simply want to group some data together. They
differ from classes in the following ways:
Some things to keep in mind
Structs are value types, not
reference types. This means they are
stored either in the stack or in-
line (if they are part of another
object that is stored on the heap)
and have the same lifetime
re-strictions as the simple data
types.
Structs do not support inheritance.
There are some differences in the
way constructors work for structs.
In particular, the compiler always
supplies a default no - parameter
constructor, which you are not
permitted to replace.