So, I (think I) understand what the in
parameter modifier does. But what it does appears to be quite redundant.
Usually, I'd think that the only reason to use a ref
would be to modify the calling variable, which is explicitly forbidden by in
. So passing by in
reference seems logically equivalent to passing by value.
Is there some sort of performance advantage? It was my belief that on the back-end side of things, a ref
parameter must at least copy the physical address of the variable, which should be the same size as any typical object reference.
So, then is the advantage just in larger structs, or is there some behind-the-scenes compiler optimization that makes it attractive elsewhere? If the latter, why shouldn't I make every parameter an in
?
in it is readonly reference in c# 7.2
this means you do not pass entire object to function stack similar to ref case you pass only reference to structure
but attempt to change value of object gives compiler error.
And yes this will allow you to optimize code performance if you use big structures.
Correct.
Yes.
There is not a requirement that a reference to an object and a reference to a variable both be the same size, and there is not a requirement that either is the size of a machine word, but yes, in practice both are 32 bits on 32 bit machines and 64 bits on 64 bit machines.
What you think the "physical address" has to do with it is unclear to me. On Windows we use virtual addresses, not physical addresses in user mode code. Under what possible circumstances would you imagine that a physical address is meaningful in a C# program, I am curious to know.
There is also not a requirement that a reference of any kind be implemented as the virtual address of the storage. References could be opaque handles into GC tables in a conforming implementation of the CLI specification.
Decreasing the cost of passing larger structs is the motivating scenario for the feature.
Note that there is no guarantee that
in
makes any program actually faster, and it can make programs slower. All questions about performance must be answered by empirical research. There are very few optimizations that are always wins; this is not an "always win" optimization.The compiler and runtime are permitted to make any optimization they choose if doing so does not violate the rules of the C# specification. There is to my knowledge not such an optimization yet for
in
parameters, but that does not preclude such optimizations in the future.Well, suppose you made an
int
parameter instead anin int
parameter. What costs are imposed?Suppose it's a
double
and you change it to anin double
. Again, now the variable cannot be enregistered into a high-performance floating point register. This not only has performance implications, it can also change program behaviour! C# is permitted to do float arithmetic in higher-than-64-bit precision and typically does so only if the floats can be enregistered.This is not a free optimization. You have to measure its performance against the alternatives. Your best bet is to simply not make large structs in the first place, as the design guidelines suggest.
in
was recently introduced to the C# language.in
is actually aref readonly
. Generally speaking, there is only one use case wherein
can be helpful: high performance apps dealing with lots of largereadonly struct
s.Assuming you have:
and
In that case, the
VeryLarge
struct will be passed by-reference without creating of defensive copies when using this struct in theProcess
method (e.g. when callingvalue.Compute()
), and the struct immutability is ensured by the compiler.Note that passing a not-readonly
struct
with anin
modifier will cause the compiler to create a defensive copy when calling struct's methods and accessing properties in theProcess
method above, which will negatively affect performance!There is a really good MSDN blog entry which I recommend to carefully read.
If you would like to get some more historical background of
in
-introducing, you could read this discussion in the C# language's GitHub repository.In general, most developers agree that introducing of
in
could be seen as a mistake. It's a rather exotic language feature and can only be useful in high-perf edge cases.This is done because of the functional programming approach. One of the major principle is that function should not have side effects, which means it should not change values of the parameters and should return some value. In C# there was no way to pass structs(and value type) without being copied only by reference which allows changing of the value. In swift there is a hacky algorithm which copies struct (their collections are structs BTW) as long as method starts changing its values. People who use swift not all aware of the copy stuff. This is nice c# feature since it's memory efficient and explicit. If you look at what's new you will see that more and more stuff is done around structs and arrays in stack. And in statement is just necessary for these features. There are limitations mentioned in the other answers, but is not that essential for understanding where .net is heading.
There is. When passing a
struct
, thein
keyword allows an optimization where the compiler only needs to pass a pointer, without the risk of the method changing the content. The last is critical — it avoids a copy operation. On large structs this can make a world of difference.