Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pattern matching case when

I write simple math tokenizer and try to use new C# pattern matching feature.

Tokenizer is quite simple:

    public IEnumerable<IToken> Tokenize(string input)
    {
        const char decimalSeparator = '.';
        string inputWithoutSpaces = input.Replace(" ", string.Empty);
        var numberBuffer = new StringBuilder();
        var letterBuffer = new StringBuilder();
        foreach (char c in inputWithoutSpaces)
        {
            switch (c)
            {
                case var _ when IsTerm(c, letterBuffer):
                    if (numberBuffer.Length > 0)
                    {
                        yield return EmptyNumberBufferAsLiteral(numberBuffer);
                        yield return new Operator('*');
                    }
                    letterBuffer.Append(c);
                    break;
                case decimalSeparator:
                case var _ when IsDigit(c):
                    numberBuffer.Append(c);
                    break;
                case var _ when IsOperator(c):
                    if (numberBuffer.Length > 0)
                    {
                        yield return EmptyNumberBufferAsLiteral(numberBuffer);
                    }
                    if (letterBuffer.Length > 0)
                    {
                        yield return EmptyLetterBufferAsTerm(letterBuffer);
                    }
                    yield return new Operator(c);
                    break;
            }
        }
        if (numberBuffer.Length > 0)
        {
            yield return EmptyNumberBufferAsLiteral(numberBuffer);
        }
        if (letterBuffer.Length > 0)
        {
            yield return EmptyLetterBufferAsTerm(letterBuffer);
        }
    }

I'm using case var _ because I want to match by condition without using if-else if chain, but I'm unable to write case when without specifying var variableName.

Is there any fancy way to perform such operation? Or it is recommended way to do these things?

like image 765
Alex Zhukovskiy Avatar asked Oct 29 '22 08:10

Alex Zhukovskiy


1 Answers

There is a "fancy" way to do pattern matching like this, using what are commonly called active patterns. C# doesn't (yet) support active patterns though, but see this answer for an example of what they might look like if/when implemented.

So using active patterns, your code would end up looking something like:

switch (c)
{
    case Term(letterBuffer):
        ...
        break;
    case decimalSeparator:
    case Digit():
        ...
        break;
    case Operator():
        ...
        break;
}

If you'd like to see this feature in a future version of C#, please upvote it on the csharplang github repo.

In the meantime, then you are limited choosing between sticking with if statements as others have said, or using when guards as you are. Which you go for really is just a matter of preferred style.

like image 181
David Arno Avatar answered Nov 15 '22 04:11

David Arno