l33t
l33t

Reputation: 19937

Pattern matching operator broken for ValueTuple?

Using .NET 6 and C# 10. Consider this simple type-check:

(object, bool) untyped = new("", false);

if (untyped is (string, bool) typed)
{
    Console.WriteLine(typed.GetType());
}

And the output:

System.ValueTuple`2[System.Object,System.Boolean]

So I managed to have the cookie and eat it at the same time. Apparently, the typed variable is of type (string, bool) and (object, bool).

I'm trying to wrap my head around this. It's tempting to state that the "compiler is broken" but maybe I've misunderstood some C# fundamentals.

Update

Example code on SharpLab.

The IL speaks for itself.

Question

Please explain the ambiguity of this type-check! Is the pattern matching operator broken?

Upvotes: 4

Views: 132

Answers (1)

canton7
canton7

Reputation: 42225

I think that's happening is that the logic is the same as:

if (c is (string, bool) d)
{
    // 'd' is a instance of 'C', not a tuple
}

public class C
{
    public void Deconstruct(out object o, out bool b) => (o, b) = ("", false);
}

SharpLab.

Which is probably more useful as e.g.:

if (c.D is (string, bool) and { Length: >0 } d)
{
    // 'd' is an instance of 'D'
}

public class C
{
    public D D { get; set; } = new();
}

public class D
{
    public int Length { get; set; }
    public void Deconstruct(out object o, out bool b) => (o, b) = ("", false);
}

SharpLab.

That is, the is (...) pattern is a positional pattern and not a type pattern. In a positional pattern, we're deconstructing the object and applying patterns to each of its parts, but the designation d applies to the object we're applying the positional pattern to, and not to a tuple constructed of its parts.

I agree this is highly confusing when we're just matching against a tuple as in your question. It does make a bit more sense in my second example above however, where c.D might be a complex expression and we want the ability to bind it to a variable while also applying patterns to it.

The actual spec doesn't seem to cover this case: it doesn't specify what type simple_designation is or what it's bound to.

Upvotes: 1

Related Questions