Reputation: 18829
The recent additions to C# 7 are great and now in the latest release we can pass ValueType
(struct
) instances to functions by-reference ('by-ref') more efficiently by using the new in
keyword.
Using either in
or ref
in the method declaration means that you avoid the extra 'memory-blt' copy of the entire struct
which is normally required in order to preserve by-value semantics. With in
, you get this benefit (passing a pointer to the source ValueType
itself), but unlike ref
, the callee won't be allowed to modify that target (enforcement by the compiler).
In addition to improving the rigor of design intent, in
has an added benefit over ref
that the call-site syntax is more relaxed than with ref
. In fact, you don't need to mention the in
keyword at the call-site; it's optional.
Anyway, I noticed that apparently you can define C# operator overloads using in
-attributed arguments.
public static bool operator ==(in FILE_ID_INFO x, in FILE_ID_INFO y) => eq(in x, in y);
// works: -----^ -----^
This is great if the by-ref semantics actually do prevail in the runtime behavior. But I would find that surprising, because even though C# lets you omit the in
keyword in method calls, the generated code at the call site does need to be different. Namely, it needs to emit (e.g.) OpCodes.Ldflda
instead of OpCodes.Ldfld
, and so forth.
And then there's also the fact that operator overloads don't have a traditional method "call site" that could be decorated with the (albeit, optional) in
keyword:
var fid1 = default(FILE_ID_INFO);
var fid2 = default(FILE_ID_INFO);
bool q = fid1 == fid2;
// ^--- in? ---^
So, does anyone know if the compiler, JIT, and runtime will honor what the code seems to be allowed to express, such that calls to operator overloads with in
-parameters will actually obtain by-ref semantics? I couldn't find any mention of the situation in the docs. Since the code shown above basically continues to work as it did without the in
markings, I suppose the alternative would be that the in
keyword is just silently ignored here?
Upvotes: 7
Views: 864
Reputation: 660397
Short answer: The compiler does the right thing. Trust the compiler.
Long answer:
An overloaded operator is simply a syntactic sugar for a static method. An invocation of an overloaded operator is simply a syntactic sugar for an invocation of that method.
That is,
public static bool operator ==(S s1, S s2) { ... }
is just a syntactic sugar for something like
public static bool op_Equality(S s1, S s2) { ... }
and
if (s1 == s2)
is just a syntactic sugar for
if (S.op_Equality(s1, s2))
So whatever behaviour holds for in
annotations on normal static methods and normal static method calls also holds for static methods which are operators, and static method invocations which are expressions that use those operators.
Upvotes: 7