1

According to all known laws of the in parameter modifier, any object passed will be passed by reference BUT be unable to be modified by the called method.

So I find this advice by Microsoft on How to write safe and efficient C# code confusing:

Declare a readonly struct to express that a type is immutable. That enables the compiler to save defensive copies when using in parameters.

Never pass a struct as an in parameter unless it's declared with the readonly modifier or the method calls only readonly members of the struct. Violating this guidance may negatively affect performance and could lead to an obscure behavior.

Why would the compiler save a defensive copy when using an "in" parameter if the method isn't allowed to modify it, anyway?

How can passing a non-readonly struct as an in parameter negatively affect performance and lead to an obscure behavior if the method isn't allowed to modify it?

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
Firld
  • 27
  • 5
  • 1
    Related https://stackoverflow.com/questions/52820372/why-would-one-ever-use-the-in-parameter-modifier-in-c (edit: maybe even duplicate) – Tim Schmelter Feb 19 '21 at 13:04
  • @TimSchmelter, related, yes, but I wouldn't say a duplicate, since that question asks what's the point of the "in" modifier, while I'm asking for clarification on Microsoft's seemingly (to me) controversial advice on the use of structs and the in modifier. – Firld Feb 19 '21 at 13:36
  • You are right, so not a duplicate, but you can find the answer there and in the [linked blog](https://devblogs.microsoft.com/premier-developer/the-in-modifier-and-the-readonly-structs-in-c/)(especially "Performance characteristics of the in-modifier"). – Tim Schmelter Feb 19 '21 at 13:43
  • @TimSchmelter, OK, I'll def take a look at that. But it will take some time. Should I go back and edit/close my question if I find the answer in that blog? – Firld Feb 19 '21 at 13:57
  • I think "save" means "avoid" – Peter Morris Aug 08 '23 at 09:53

1 Answers1

1

For example:

public struct Test
{
    public int Value;
    public void SetValue(int value) => Value = value;
}
public static void Method(in Test test)
{
     test.SetValue(5);
     Console.WriteLine(test.Value); // 0
 }

This will compile just fine. If I understand the case correctly the copy will not be created when the constructor is called, but when any methods that may mutate the value are called.

Making the struct readonly will prevent any mutating methods from being called, so hidden copies will be avoided.

There are also good arguments for why mutable structs are evil, so I would advocate just making all structs readonly. I.e.

public readonly struct Test
{
    public int Value { get; }
    public Test(int v) => Value = v;
    // Any "mutating" method should create a copy instead
    public Test WithValue(int v) => new Test(v); 
}
JonasH
  • 28,608
  • 2
  • 10
  • 23
  • But why would the compiler generate a defensive copy, at all? If "in" says "this will NOT be modified", what's the point? Is it only for cases like your example? – Firld Feb 19 '21 at 13:40
  • @Firld The compiler has to enforce the "this will not be modified" statement. If it cannot prove that it will not be modified it has to create a defensive copy. If the struct is marked as readonly that proof is trivial. But proving something can be difficult, and the compiler is likely to just create a defensive copy in any non trivial cases. – JonasH Feb 19 '21 at 16:15