Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch syntax for using only conditional patterns? #14615

Closed
dsaf opened this issue Oct 19, 2016 · 6 comments
Closed

Switch syntax for using only conditional patterns? #14615

dsaf opened this issue Oct 19, 2016 · 6 comments
Labels
Area-Language Design Language-C# New Language Feature - Out Variable Declaration Out Variable Declaration New Language Feature - Pattern Matching Pattern Matching Resolution-By Design The behavior reported in the issue matches the current design

Comments

@dsaf
Copy link

dsaf commented Oct 19, 2016

Consider an example below where a string input is read, then attempted to be parsed to different numeric types and then compared to the max value of a respective numeric type.

In this case the source type being matched is always string but the target type can be different:

http://tryroslyn.azurewebsites.net

using System;

public class Sample
{
    public void Test()
    {
        switch(Console.ReadLine())
        {
            case string raw when TryGet<int>(raw, out var parsed):
                Console.WriteLine(parsed == int.MaxValue);
                break;
            case string raw when TryGet<float>(raw, out var parsed):
                Console.WriteLine(parsed == float.MaxValue);
                break;
            case string raw when TryGet<double>(raw, out var parsed):
                Console.WriteLine(parsed == double.MaxValue);
                break;
        }
    }

    public bool TryGet<T>(object obj, out T val)
    {
        val = default(T);
        return true;
    }
}

Does this mean that if-else would be a better choice? But it has a very weird scoping rules (in master) which force me to use different variable names thus increasing a chance of bugs:

using System;

public class Sample
{
    public void Test()
    {
        var raw = Console.ReadLine();

        if (TryGet<int>(raw, out var parsed1))
            Console.WriteLine(parsed1 == int.MaxValue);
        else if (TryGet<float>(raw, out var parsed2))
            Console.WriteLine(parsed1 == float.MaxValue);
        else if (TryGet<double>(raw, out var parsed3))
            Console.WriteLine(parsed2 == double.MaxValue);
    }

    public bool TryGet<T>(object obj, out T val)
    {
        val = default(T);
        return true;
    }
}

Would the following switch syntax extension make any sense, or am I just doing something wrong?

using System;

public class Sample
{
    public void Test()
    {
        switch(Console.ReadLine() raw)
        {
            case when TryGet<int>(raw, out var parsed):
                Console.WriteLine(parsed == int.MaxValue);
                break;
            case when TryGet<float>(raw, out var parsed):
                Console.WriteLine(parsed == float.MaxValue);
                break;
            case when TryGet<double>(raw, out var parsed):
                Console.WriteLine(parsed == double.MaxValue);
                break;
        }
    }

    public bool TryGet<T>(object obj, out T val)
    {
        val = default(T);
        return true;
    }
}

Relevant opinions:

http://stackoverflow.com/questions/449273/why-the-switch-statement-and-not-if-else
http://stackoverflow.com/questions/427760/when-to-use-if-else-if-else-over-switch-statments-and-vice-versa

@alrz
Copy link
Contributor

alrz commented Oct 19, 2016

Related: #13401

@svick
Copy link
Contributor

svick commented Oct 19, 2016

Would declaring raw as a normal variable and then using case * when be acceptable? (It won't work in master, since wildcard patterns are not supported yet.)

var raw = Console.ReadLine();
switch(raw)
{
    case * when TryGet<int>(raw, out var parsed):
        Console.WriteLine(parsed == int.MaxValue);
        break;
    case * when TryGet<float>(raw, out var parsed):
        Console.WriteLine(parsed == float.MaxValue);
        break;
    case * when TryGet<double>(raw, out var parsed):
        Console.WriteLine(parsed == double.MaxValue);
        break;
}

Though this version and your last version are not actually using the switch expression, so maybe a special syntax for that could make sense?

var raw = Console.ReadLine();
switch
{
    case when TryGet<int>(raw, out var parsed):
        Console.WriteLine(parsed == int.MaxValue);
        break;
    case when TryGet<float>(raw, out var parsed):
        Console.WriteLine(parsed == float.MaxValue);
        break;
    case when TryGet<double>(raw, out var parsed):
        Console.WriteLine(parsed == double.MaxValue);
        break;
}

@gafter
Copy link
Member

gafter commented Oct 19, 2016

@dotnet/ldm FYI, here is an issue pushing back on the revised scoping rules for if-then-else.

@MadsTorgersen MadsTorgersen added the Resolution-By Design The behavior reported in the issue matches the current design label Oct 19, 2016
@MadsTorgersen
Copy link
Contributor

Thanks for raising the issue!

Switch statements are for when you have conditions that can apply to the same expression. I don't think we are going to change that.

Currently, your scenario is best handled by the if-statement. The fact that you have to use different variable names is by design - although we did discuss it quite a bit. In the end we found that the value of making the variable available outside of the if condition outweighed the nuisance of "polluting the namespace" and having to come up with different variable names.

I would recommend using better variable names than parsed1 etc!

In the future we may consider something like "active patterns" (see e.g. #206) which would allow you to express the parsing itself as a pattern to put in the case clause.

Mads

@bbarry
Copy link

bbarry commented Oct 19, 2016

The scoping rules of that switch statement seem weirder to me than they do for the if statements. I wouldn't expect to be able to re-use a variable name between case statements (even having followed and understanding the current design of the feature).

@dsaf
Copy link
Author

dsaf commented Oct 19, 2016

@MadsTorgersen I understand, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Language Design Language-C# New Language Feature - Out Variable Declaration Out Variable Declaration New Language Feature - Pattern Matching Pattern Matching Resolution-By Design The behavior reported in the issue matches the current design
Projects
None yet
Development

No branches or pull requests

6 participants