15

Is there a reason Microsoft decided to make these structs?

All three are mutable. I would find them much easier to deal with if they were either immutable, or if they were reference types.

If there are reasons they must be structs, why are they mutable?

Flash
  • 13,804
  • 11
  • 65
  • 91
  • Could you elaborate on how their mutable `struct`ness is causing you issues? – Damien_The_Unbeliever Jan 07 '13 at 08:57
  • 1
    @Damien_The_Unbeliever for example: `foreach (Point r in points) { r.X += 1; }` – Flash Jan 07 '13 at 09:03
  • Related, possible duplicate: [Why are System.Windows.Point & System.Windows.Vector mutable?](http://stackoverflow.com/questions/8920080/why-are-system-windows-point-system-windows-vector-mutable) – sloth Jan 07 '13 at 09:14
  • @DominicKexel, The question is related, though the accepted answer is only relevant to WPF. – Rotem Jan 07 '13 at 09:15
  • @Rotem That's why I didn't vote to close :-) – sloth Jan 07 '13 at 09:17
  • @Andrew Your code example only fails to work because you are using `foreach`, which boxes the values. It does work in a simple `for` loop. **All three structs are fully mutable**. – Rotem Jan 07 '13 at 09:31
  • @Rotem Yes, but I guess to me it reads like it should work because `r.X += 1` implies that `r` has reference semantics. Another example is that if I'm allowed to do `r.X += x`, I should be allowed to make `void offsetX(Point p, int xOffset)` work without resorting to `ref`. I can make it work knowing that it's a value type - but why must Microsoft confuse me? – Flash Jan 07 '13 at 09:41
  • The fact that `r.X += 1` works only implies that it's a writable field, not that it is a value or reference type. In your method you must use `ref` because otherwise you would be modifying a *copy* of the `Point`, which is not what you want. – Rotem Jan 07 '13 at 09:43

2 Answers2

20

Why are they Structs

Value Semantics
There is no essential difference between two identical instances of these values. Any Point with coordinates, [2,3] is equal to any other point with the same coordinates, much like any two ints with similar value are equal. This is in conformance with the design guideline:

It logically represents a single value, similar to primitive types (integer, double, and so on).

Performance

Value types are cheaper to allocate and deallocate.

There is often requirement to create many instances of these values. Structs cost less to create, and if they are local values, they will be created on the stack, relieving pressure from the GC.

Size
Let's consider the size of these values:
Point : 8 bytes
Size: 8 bytes
Rectangle: 16 bytes

For Point and Size, their size is the same as a reference to a class instance would be in a 64-bit system.

Quotes taken from Microsoft's guidelines: Choosing Between Classes and Structures

Why are they Mutable

These structs are fully mutable. This is done (against the guidelines) for the sake of performance, as it avoids the need to create new values for modification operations.

Regarding the OP's code example in the comments:

Point[] points = new Point[] { new Point(0,0), new Point(1,1), new Point(2,2) };

foreach (Point p in points)
{
    p.X += 1; 
}

The only reason this foreach fails, is because p is boxed to object in order to provide iteration, and you Cannot modify the result of an unboxing conversion, (thanks Rajeev) the iterator returns the data by value, and you would only be making changes to the copy of the value.

This works fine:

for (int i = 0; i < points.Length; i++)
{
    points[i].X += 1;
}
Rotem
  • 19,723
  • 6
  • 57
  • 101
  • @Rotem `Rectangle` violates three out of four of Microsoft's guidelines according to that link. – Flash Jan 07 '13 at 09:05
  • @Andrew I agree! But I guess the fact this is logically a value outweighed the other points. – Rotem Jan 07 '13 at 09:06
  • @Rotem I see your point. Maybe the question should be why are they mutable? – Flash Jan 07 '13 at 09:10
  • @JLRishe No, they are mutable. `Rectangle` for instance has an `Offset` method to change its coordinates. The third is that to me a `Rectangle` doesn't represent a single value, but I suppose that's subjective :) – Flash Jan 07 '13 at 09:20
  • @Andrew My mistake. In that case I too find it odd that they are mutable. I have rescinded my prior comment. – JLRishe Jan 07 '13 at 09:22
  • @Andrew: I really dislike the way that "unified value" guideline is written. A mutable struct is the data type which best encapsulates a bunch of *independent* but related values *without* encapsulating a collective identity. The values in an immutable type are much harder to use independently than those of an exposed-field structure, and exposed references to mutable objects cannot avoid encapsulating identity. The greater the independence of a type's members, the *stronger* the imperative for it being a structure rather than a class. – supercat Oct 04 '13 at 21:35
  • @Rotem, I think compiler will translate the foreach loop on Point[] to normal for loop right? Because it does that for int[]. So how come the point will get boxed? Am I missing something here? – Rajeev Jul 06 '17 at 12:37
  • @Rajeev I don't understand what you mean. You are definitely not allowed to change the value of the iteration variable in a `foreeach`, e.g. `foreach (int i in myInts) i += 1;`. This results in a compiler error. – Rotem Jul 06 '17 at 12:51
  • @Rotem, I just have doubt regarding your statement _"The only reason this foreach fails, is because p is boxed to object in order to provide iteration"_ whey there is a need of boxing here? – Rajeev Jul 06 '17 at 13:58
  • @Rajeev I think you're right, it would only get boxed if the container is not generic. I don't know based on what information I wrote the answer, it was over 4 years ago. Nevertheless, the foreach is still not possible because the iterator is returning a copy of the data. I've modified the answer to reflect this information. – Rotem Jul 06 '17 at 14:09
2

Microsoft doesn't need to define these structures as a class.

These are basically small structures.

If these are defined as a class, for Point structure, same coordinates could refer to different objects in memory. Defining as a struct, we know there is no difference between different points with same coordinates. It means they are value types. Value types are almost always cheaper to allocate. Look at their size;

Point : 8 bytes
Size: 8 bytes
Rectangle: 16 bytes

Who wants to allocate a new memory part every time they create a Point(1,2)?

Soner Gönül
  • 91,172
  • 101
  • 184
  • 324