2

C# 7.2 added readonly structs and the in modifier for method parameters. However, you get a compiler error when you try to use these structs with reference-like semantics in lambda expressions:

public readonly struct Point {
    public Struct(int x, int y) {
        X = x;
        Y = y;
    }
    public int X { get; }
    public int Y { get; }
}

public IEnumerable<Point> FindMatching(
    this IEnumerable<Point> points, 
    in Point toMatch) {
    return point.Where(p => p.X == point.X && p.Y == point.Y);
}

Compiling returns an error:

error CS1628: Cannot use ref or out parameter 'toMatch' inside an anonymous method, lambda expression, or query expression.

It's not a ref or out parameter, however.

Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
Jimmy Bogard
  • 26,045
  • 5
  • 74
  • 69
  • 4
    @Servy I disagree with that dup; it isn't asking why we can't use `ref`/`out` here. It is asking specifically about a C# 7.2 feature, so an answer from 2009 **cannot possibly** answer this directly – Marc Gravell Feb 01 '18 at 14:22
  • @MarcGravell And the reason is the same. What matters is that the parameter is passed by reference, not how the referenced parameter can or can't be mutated. – Servy Feb 01 '18 at 14:23
  • `The in modifier on parameters, to specify that an argument is passed by reference but not modified by the called method.` So, in fact it's a `ref` but which will disallow the modification of the content. Source: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-7-2#reference-semantics-with-value-types – Gusman Feb 01 '18 at 14:25
  • 2
    @Servy I fundamentally disagree with you here – Marc Gravell Feb 01 '18 at 14:25
  • 1
    @MarcGravell How do you think the duplicate fails to answer the question? What about it doesn't answer the question? – Servy Feb 01 '18 at 14:26
  • 2
    @Servy because that question explains why you can't use `ref` / `out` in a lambda. The answer to "why does it complain about `ref` / `out` when I use `in`" is simply: because `in` is actually a `ref`. Pointing to that answer *simply doesn't answer that*. Especially given that the compiler message is very confusing and doesn't help here. I'd agree that they're strongly related questions, but they're not the same. – Marc Gravell Feb 01 '18 at 14:28
  • @MarcGravell And *the explanation for why you can't use `out/ref` applies *exactly* to `in`. You appear to have just looked at the title and *ignored the actual answer*, which explains *why* you can't do it. That *explanation* applies perfectly to `in`. You have merely *stated* that the error applies, and not explained *why* the error message exists. Saying, "no the error isn't wrong" isn't answering the question. The duplicate, which demonstrates what would break if this were allowed *does* answer the question. – Servy Feb 01 '18 at 14:30
  • @MarcGravell The question isn't asking why the error message doesn't mention `in`. This isn't a bug report. It's asking *why the behavior isn't allowed*. The duplicate answers that question. – Servy Feb 01 '18 at 14:31
  • 1
    The question states an error message and doesn't ask any question. We're left to infer whether the question is why an error is generated at all, or why *that* error is generated. Whether closing as a duplicate is correct depends on that. –  Feb 01 '18 at 14:33

1 Answers1

4

Behind the scenes, in is a ref parameter, but with fancy semantics. The same as out is a ref parameter with fancy semantics. The compiler message could be clearer, perhaps - that might be a good bug to log on the Roslyn github. But: it is correct to error. I would agree that the error should explicitly mention in parameters.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900