0

Continue to :When to use struct?.

After reading Microsoft's rules about defination of stucts, I feel puzzled at:

  1. It has an instance size under 16 bytes.:How to calculate a size under 16 bytes? Add each variable inside the struct together? If yes, probably most of variables cannot be used with such a type (example: If you nest a string or some very complicated type inside a struct, this size will be much larger than 16 bytes).

  2. It is immutable.:What does this mean? Is this meaning "the memory assigned to the variable cannot be changed once it's created"? And that's just the reason to explain when a struct is created, it will be soon garbaged (For a short-lived time)?

Many thanks!

Community
  • 1
  • 1
  • 1. Yes, 2. Yes but I don't understasnd the second part of your statement, the memory won't be garbage collected until references to it are garbage collected. So, what is the question? – Jodrell Apr 23 '14 at 07:50
  • 1-No, an string is a reference in an struct, so it's size is sizeof(IntPtr) in the struct unless you use an attribute to fix its length and make it part of it. – Gusman Apr 23 '14 at 07:57

5 Answers5

0

The size of the struct is only the struct itself, not of objects it refers to that lives on the heap.

For a string, that's a reference, which adds either 32 bits (4 bytes) or 64 (8) depending on the CPU technology you're running under. The actual string is on the heap and is not relevant to the purpose of this rule.

The purpose of this rule is that when you pass structs around, they're copied, byte for byte, and when they start to become big, that copying tends to add more overhead than what you gain from avoiding putting pressure on the garbage collector.

There are numerous questions here on Stack Overflow related to how to obtain the size of a struct (or something meaningful in this regard anyway), I suggest you do a search. In short, no, it's not as easy as simply totalling the size of each individual field, as there may be padding and alignment that impacts this.

An immutable struct is one that doesn't change after given a value. The easiest (but by no means the only) way to do this is to make all the fields readonly, meaning that once given a value through a constructor, they can't be changed (easily).

The purpose of this rule is that there are hidden gotchas related to boxing, unboxing, copying, etc. that will throw a spanner in the works if you create mutable structs.

There's numerous questions on this topic as well, search for "Mutable structs are evil".


Here's an example of "evil mutable structs". Given this code:

public struct Struct
{
    public int Value;
    public void Change()
    {
        Value++;
    }
}

private Struct _Struct = new Struct();
public Struct GetStruct()
{
    return _Struct;
}

public Struct StructProperty
{
    get
    {
        return _Struct;
    }
}

This will "work", it will output first 0 and then 1, the struct was changed.

void Main()
{
    _Struct.Value.Dump();
    _Struct.Change();
    _Struct.Value.Dump();
}

This will not, it will output 0 and 0, because the copy returned from the property was changed.

void Main()
{
    _Struct.Value.Dump();
    StructProperty.Change();
    _Struct.Value.Dump();
}

Neither will this, same result:

void Main()
{
    _Struct.Value.Dump();
    GetStruct().Change();
    _Struct.Value.Dump();
}

Note: If your intended goal was to actually not disturb the underlying struct, then this "works", from that standpoint, but all my experience with mutable structs tells me that sooner rather than later you're moving structs around and implicitly expecting them to behave like instance references.

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
  • Why must all the values immutable? From "Why are mutable structs evil?" I see that to avoid the problem of copying again and again, but if you image I have an exposed method to change the inner private variable of a struct, and it won't do anything about copy at all. So just not to make a struct as a public property to the ouside. –  Apr 25 '14 at 07:08
  • If the struct has already been copied, it doesn't matter what the method does. There's enough cases where a struct is copied and you don't think about it, and the compiler doesn't warn about it, to make it a bug nightmare. Note that "structs should be immutable" is a rule. Rules can be broken, *but only if you know what you're doing*. My advice, don't make mutable structs at all. – Lasse V. Karlsen Apr 25 '14 at 07:26
0

1.It has an instance size under 16 bytes.:How to calculate a size under 16 bytes? Add each variable inside the struct together?

In a nutshell, yes. Since this is just a guideline, it does not have to be exact.

If yes, probably most of variables cannot be used with such a type (example: If you nest a string or some very complicated type inside a struct, this size will be much larger than 16 bytes).

String is a class. Thus, a variable of type string points to a location in memory and takes up either 32 or 64 bit. And yes, nesting complicated types inside a struct might not be such a good idea.

2.It is immutable.:What does this mean? Is this meaning "the memory assigned to the variable cannot be changed once it's created"? And that's just the reason to explain when a struct is created, it will be soon garbaged (For a short-lived time)?

No, this has nothing to do with memory. It just means that its state cannot be modified.

Example: This is a mutable struct:

struct MyStruct
{
    private int someValue;

    public MyStruct(int initialValue) { someValue = initialValue; }

    public int SomeValue { get; set; } // someValue can be modified here through the setter
}

This is an immutable struct:

struct MyStruct
{
    private int someValue;

    public MyStruct(int initialValue) { someValue = initialValue; }

    public int SomeValue { get; } // No way to modify someValue
}

Further reading: Why are mutable structs “evil”?

Community
  • 1
  • 1
Heinzi
  • 167,459
  • 57
  • 363
  • 519
  • Thanks! but if I use the stuct as a public property and call its inner method to change the value, it will do copy. But your codes don't seem copying a new struct. It will change the same struct itself (From "Why are mutable structs evil?") –  Apr 25 '14 at 07:04
  • If the property returns the struct, you've already gotten a copy of it. So this: `SomeClass.StructProperty.ChangeTheStruct();` will change the copy. – Lasse V. Karlsen Apr 25 '14 at 07:27
0

I would personally suggest staying away from structs in C# unless you absolutely need them for things such as interop, or actual performance benefits (which are likely small).

Generally structs represent a concrete data structure, which you never need to change. You can't reference structs like you normally do with classes. when you create a new reference to a strucutre, you are essentially making a copy of the entire structure. Any chance you make to this new struct has no effect on the original.

A quick example of how structs work (versus normal classes)

var s = new SomeStruct();
s.SomeField = 5;

var y = s;
y.SomeField = 10;

Console.WriteLine(s.SomeField); //Prints 5
Console.WriteLine(y.SomeField); //Prints 10
Dan
  • 734
  • 1
  • 9
  • 23
  • But why Microsoft invents Struct? Since you think it's useless……? –  Apr 25 '14 at 07:05
  • The biggest purpose of structs is to create more complex data types that store the entire data whenever moved around. The best example is a Point class which could be passed around just like you would an integer (you pass both X and Y). It makes programming more structured; instead of passing (or even returning) X and Y for an object's position, you simply pass a nicely formatted structure. In C#, their main purpose is backwards compatibility, since C# provides interop with native (C++/C) libraries. – Dan Apr 26 '14 at 20:08
0

How to calculate a size under 16 bytes? Add each variable inside the struct together?

Generally, yes. The size of a value type is calculated by summing the size of its fields. If the struct has two fields of type int, it will have 4+4 = 8 bytes. If you were to calculate the size of a reference type, you'd have to account for its header (reference to a TypeHandle and a syncblk), which is 8 bytes wide on 32-bit systems and 16 bytes wide on a 64-bit system.

If yes, probably most of variables cannot be used with such a type (example: If you nest a string or some very complicated type inside a struct, this size will be much larger than 16 bytes).

No, because the value type would contain a pointer to the string, not the string itself. This pointer would be 4 bytes on 32-bit systems and 8 bytes on 64-bit systems. When you pass the value type around and it gets copied, only the reference to the string will be copied.

It is immutable.:What does this mean?

It means the observable data cannot change. If you expose an field/property called Age, or a method called GetAge(), these must always return the same value once the value type has been created. See also Why are mutable structs evil?

Community
  • 1
  • 1
dcastro
  • 66,540
  • 21
  • 145
  • 155
  • Maybe the calculation of the whole size is wrong: For a struct nested with a class type, we should calculate all the memory taken on the Stack instead of that on the heap. –  Apr 25 '14 at 07:06
  • @CA55CE37 What do you mean? A value type's size doesn't depend on its location, or on whether it's a class's field or a local variable. – dcastro Apr 25 '14 at 07:18
0

A struct is not an object--it's a bunch of variables stuck together with duct tape. In some cases where one semantically wants an object, but a struct may be an adequate lower-cost alternative. In other cases, one wants a bunch of variables stuck together with duct tape.

The behavior of mutable structures is unlike the behavior of objects. Thus, for a struct to behave like an object, it must be immutable. Further, unlike the cost of passing or copying reference variables which is independent of the size of the thing referenced, the cost of passing or copying structs increases with size. If a structure is large and is passed around a lot, that extra cost can be significant. If a structure isn't passed around much, the size really won't matter. On the other hand, the performance improvement from replacing a small class with a struct is much greater than the maximum possible improvement that could be achieved with a larger one.

If what one wants is a bunch of variable stuck together with duct tape (such as the coordinates of a point), one should use a struct consisting of a bunch of public fields. A two-second glance at such a struct will reveal that it's pretty much like any other such struct other than the names and tapes of the fields, and possibly its overrides for Equals, HashCode, and ToString(). Although it's sometimes reasonable for structures to have "utility" methods, it's often a good idea to have methods which modify structures be static and accept the structure in question as a ref parameter. This will help visually reinforce the fact that the method is acting upon an aggregation of variables, rather than an object, and will also avoid cases where a compiler might substitute a copy of a struct for the "real" one.

The MS guidelines are pretty good if one is trying to design a structure which is supposed to behave like an object. If, however, one wants a bunch of variables stuck together with duct tape, one should ignore them--especially the "single entity" part. The fact that the coordinates of a point have meaning as independent numbers should be seen as part of the reason Point should be (and is) a struct, rather than being an argument against it.

supercat
  • 77,689
  • 9
  • 166
  • 211