I want to minimize copying of structs in a maths library and read about the C# 7.2 in
modifier, especially the warnings when using it with mutable structs.
It so happens that I have this mutable struct:
public struct Quaternion
{
public float W;
public float X;
public float Y;
public float Z;
}
So far, the library has methods like this, where parameters are passed by ref
:
public static void Dot(ref Quaternion left, ref Quaternion right, out float result)
=> result = left.W * right.W + left.X * right.X + left.Y * right.Y + left.Z * right.Z;
From the MSDN documentation, I learned that if I change these to in
parameters, as long as I only access fields of a mutable struct, no defensive copy will occur since the compiler sees I am not modifying the mutable struct:
public static void Dot(in Quaternion left, in Quaternion right, out float result)
=> result = left.W * right.W + left.X * right.X + left.Y * right.Y + left.Z * right.Z;
First question: Is my understanding of that behavior correct?
Second, silly question: If in one of such methods which accept the struct as an in
parameter, will the compiler copy it if I call another method accepting them as in
parameters? An example:
public static void Lerp(in Quaternion start, in Quaternion end, float amount,
out Quaternion result)
{
float inv = 1.0f - amount;
if (Dot(start, end) >= 0.0f) // will 2 copies be created here?
{
result.W = inv * start.W + amount * end.W;
result.X = inv * start.X + amount * end.X;
result.Y = inv * start.Y + amount * end.Y;
result.Z = inv * start.Z + amount * end.Z;
}
else
{
result.W = inv * start.W - amount * end.W;
result.X = inv * start.X - amount * end.X;
result.Y = inv * start.Y - amount * end.Y;
result.Z = inv * start.Z - amount * end.Z;
}
result.Normalize();
}
I am pretty sure it should not create copies - how else would I prevent copies from the call side then? But as I am not sure, I better ask first before creating a mess.
Addendum
Reasons I want to change ref
to in
:
- (
static
)readonly
fields (e.g. specific constant quaternions) cannot be passed asref
arguments. - I cannot specify
ref
on operator parameters, but I can usein
. - Continually specifying
ref
on the call site is ugly. - I'm aware I have to change the call site everywhere, but that is okay since this library will only be used internally.