garty
garty

Reputation: 416

Pattern matching and scope - If statements

So, I've been racking my brains or rather lack thereof over the following snippet of code:

public static void Main()
    {
        string a = "sdasd";
        object b = (object)a;
        object c = (object)a;
        
        if (b is string mystring) {
         Console.WriteLine(mystring);
        }
        if (c is string mystring) {
         Console.WriteLine(mystring);
        }
    }

(https://dotnetfiddle.net/tUTcOR)

Attempting to compile the above code will produce a compile-time error:

A local variable or function named 'mystring' is already defined or in this scope

I am lead to believe that anything declared in the expression of an if a statement is scoped to the same scope of said statement, so in the above example 'main' would define the scope. This makes sense.


Referring to the MSDN docs:

public static double ComputeAreaModernIs(object shape)
{
    if (shape is Square s)
        return s.Side * s.Side;
    else if (shape is Circle c)
        return c.Radius * c.Radius * Math.PI;
    else if (shape is Rectangle r)
        return r.Height * r.Length;
    // elided
    throw new ArgumentException(
        message: "shape is not a recognized shape",
        paramName: nameof(shape));
}

Let's examine both of those rules in detail, beginning with scope. The variable c is in scope only in the else branch of the first if statement. The variable s is in scope in the method ComputeAreaModernIs. That's because each branch of an if statement establishes a separate scope for variables. However, the if statement itself doesn't. That means variables declared in the if statement are in the same scope as the if statement (the method in this case.) This behavior isn't specific to pattern matching, but is the defined behavior for variable scopes and if and else statements.

The variables c and s are assigned when the respective if statements are true because of the definitely assigned when true mechanism.

(https://learn.microsoft.com/en-us/dotnet/csharp/pattern-matching)


Now given the above explanation, I'd like to take note of two specific points, and provide another code snippet:

That's because each branch of an if statement establishes a separate scope for variables

AND

The variables c and s are assigned when the respective if statements are true

public static void Main()
{
    string a = "sdasd";
    object b = (object)a;
    object c = (object)a;
    
    if (b is string mystring) {
     Console.WriteLine(mystring);
    }else if (c is string mystringg)  {
     Console.WriteLine(mystringg);
    }else if (c is int mystringg) {
     Console.WriteLine(mystringg.ToString());
    }
        
}

(https://dotnetfiddle.net/FFZhyl)

So, given that c is string mystringg, and c is int mystringg are defined in separate scopes (as per the first quote noted above), and both can never evaluate to true (either or) meaning only one of the two will ever be initialized (as per the second quote above), why does the above code not compile?

Upvotes: 1

Views: 3038

Answers (1)

Panagiotis Kanavos
Panagiotis Kanavos

Reputation: 131374

Notice this segment :

That's because each branch of an if statement establishes a separate scope for variables. However, the if statement itself doesn't.

That means variables declared in the if statement are in the same scope as the if statement (the method in this case.) This behavior isn't specific to pattern matching, but is the defined behavior for variable scopes and if and else statements.

This means that mystring has method scope. If you test the code in Sharplab.io you'll see that this code :

    string a = "sdasd";
    object b = (object)a;
    object c = (object)a;

    if (b is string mystring) {
       Console.WriteLine(mystring);
    }
    if (c is string mystring1) {
       Console.WriteLine(mystring1);
    }

is translated to this :

    string text = "sdasd";
    object obj = text;
    object obj2 = text;
    string text2 = obj as string;
    if (text2 != null)
    {
        Console.WriteLine(text2);
    }
    string text3 = obj2 as string;
    if (text3 != null)
    {
        Console.WriteLine(text3);
    }

Upvotes: 4

Related Questions