1

I know there are approximately 1,000 questions on the C# struct. I want to iterate I understand the value semantics, the performance benefits of stackallocs, etc. My specific question stems from this msdn article on when to use a struct over a class. MSDN struct vs class C#

First, they speak to the benefit of inline data for containers, specifically arrays. One allocation, and the un-user-definable default initialization of all structs in the array. However, they also emphasize that structs should be immutable.

If I declare a mystuct[] s = new mystruct[16];, I have 16 mystructs with default values inline. If I have created a 'kosher' struct with no external mutability as recommended, how is the construct of any use to me? I doubt I intend to have an array of 0-integrals and nulls exclusively.

Do they mean immutable when functioning as a record or a property return only, ie singular data transport?

If the specific conflict between default array initialization, and recommended immutability has been broached before, please mark as a duplicate. Thanks for any insight.

schulmaster
  • 413
  • 5
  • 16

2 Answers2

1

There is no actual contradiction between the two:

after you do var s = new mystruct[16];, it's true that you have and array of 16 instances of mystruct initialized to the default value.

However, doing s[0] = new mystruct(<arguments list here>) does not mutate the struct at the first cell of the array, it replaces it with the new struct.

So the struct it self is still immutable.

Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
  • If the intended default initialization is supposed to be either for benefit of performance or convenience, but then I have to loop over every default initialized element, overriding all fields with values based on a user defined constructor, why not let me specify the values of default initialization? I can't see the benefit of two member-wise passes over the structure, even if only one allocation took place. – schulmaster Sep 02 '18 at 20:34
  • but you can initialize an array with your user defined data: `var x = new mystruct[] { new mystruct(), new mystruct(), new mystruct() };` will create an array with 3 fully initialized instances of `mystruct`.... – Zohar Peled Sep 02 '18 at 20:38
  • If I have a 256 element array, and I have one int in my struct I want to be `-1` instead of `0`, an initialization list isn't a practical solution. – schulmaster Sep 02 '18 at 20:40
  • 1
    @schulmaster how would you initialize a new `int` array? – Parrish Husband Sep 02 '18 at 20:41
  • 1
    @schulmaster no, it wouldn't. but a loop will do nicely. If you are asking what is the benefit of initializing the array "cells" when initializing the array, I can't answer that of the top of my head, I'll have to do some reading and it's approaching midnight here, so not today. I'm pretty sure there's a good reason behind it - c# was designed by some smart people. – Zohar Peled Sep 02 '18 at 20:44
  • @ParrishHusband I see your point, but when using a data structure based on value, I expect a little more power than primitive value alone affords. I can write a constructor for my struct, but not for int, but i have to have my structure default initialized(when arrayed) so I can turn around and overwrite all those writes. If I'm enforcing immutability, I can't even target the specific fields that differ from default. The struct array is presumably defined around efficiency, and a reliable way to yield good cache performance when iterated over. I just find these restrictions to be defiant. – schulmaster Sep 02 '18 at 20:46
  • @schulmaster can you post your struct? – Parrish Husband Sep 02 '18 at 20:54
  • @ParrishHusband There is no specific struct, this was more based on theory. The heavy reference semantics of C# make spatial cache performance in several random-access sequential containers sub-optimal. The inline storage of value types helps combat this. However, if I am concerned with efficiency, two full-bore linear passes over the data is not an alimentary concept, especially if one is redundant. If mystruct has three value primitives, and I want only one of the three to differ from default, I am overriding two thirds of the structure with the values already there. – schulmaster Sep 02 '18 at 20:59
  • Note that there is no guarantee for a struct to be on the stack: `"value types are stored on the stack when the value is a local variable or temporary that is not a closed-over local variable of a lambda or anonymous method, and the method body is not an iterator block, and the jitter chooses to not enregister the value"` – Parrish Husband Sep 02 '18 at 21:01
  • @ParrishHusband I have no qualms about the array's being on the heap. It is a reference type after all, always assumed to be long term once not null, per the article you linked. Once dereferenced however, the ability to not have to chase sequential references, having inline values instead, is beneficial to spatial locality. Superior locality of reference is even highlighted by the msdn article. – schulmaster Sep 02 '18 at 21:03
  • @schulmaster We're not looking into specific structs, so I wouldn't be suprised if there are cases where the expected performance gains are nullified. I believe this just stresses the importance of choosing `struct` vs `class` where it actually makes sense. The only way to know for sure in some cases would be through good profiling. – Parrish Husband Sep 02 '18 at 21:10
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/179283/discussion-between-schulmaster-and-parrish-husband). – schulmaster Sep 02 '18 at 21:11
1

The immutability being talked about is via the struct's methods, not the value of the struct itself. An instance of a struct can always be mutated through assignment - think of the integer loop variable in a for loop; it gets changed on each pass through the loop.

But, it wouldn't make sense for the framework's System.Int32 struct (i.e., int) to have a DoubleIt method that causes the underlying integer to have its value doubled without some obvious assignment operation (like how ++i; is actually i=i+1;).

Consider the difference between string.Replace and StringBuilder.Replace. The System.String class is immutable. The Replace method on a string returns a new string instance that represents the original string after the replacement operation. StringBuilder's Replace does the replacement in place, mutating the internal object.

So, if i create an integer array:

var ar = new int[] {1, 2, 3, 4};

I can alway mutate the contents of that array (a System.Array instance, a reference type) by array assignment:

 ar[2] = 200;

What would make no sense would be to call some mutating method on that (integer) array element.

Parrish Husband
  • 3,148
  • 18
  • 40
Flydog57
  • 6,851
  • 2
  • 17
  • 18