Roslyn: Proposal: Better pattern matching with generic types

Created on 30 Dec 2016  路  10Comments  路  Source: dotnet/roslyn

Predecessor: #5023

Actually in the parent issue, pattern matching was not highlighted. Hence this new issue. Given these classes-

abstract class Result<T> { }
sealed class Success<T>:Result<T>
{
    public T Value {get;}
    public Success(T value) {Value = value;}
}
sealed class Error<T>:Result<T>
{
    public Exception Ex {get;}
    public Error(Exception ex) {Ex = ex;}
}

And this static method-

static Result<T> Try<T>(Func<T> fun)
{
    try
    {
        return new Success<T>(fun());
    }
    catch (Exception e)
    {
        return new Error<T>(e);
    }
}

I want to write

var res = Try(SomeMethod);
if (res is Success ok)
    Console.WriteLine(ok.Value);
else
    Console.WriteLine((res as Error).Ex.Message);

instead of

var res = Try(SomeMethod);
if (res is Success<int> ok)
    Console.WriteLine(ok.Value);
else
    Console.WriteLine((res as Error<int>).Ex.Message);

Another option can be discarding the type with '_'-

var res = Try(SomeMethod);
if (res is Success<_> ok)
    Console.WriteLine(ok.Value);
else
    Console.WriteLine((res as Error<_>).Ex.Message);
Area-Language Design Discussion New Language Feature - Pattern Matching

Most helpful comment

I keep seeing the title and thinking "ooh, genetic types, what's that?"

@jnm2 Genetic types are great for inheritance.

All 10 comments

Look at #6739, specifically the use of enums as algebraic data types. The Option<T> example is very similar to your Result<T> use case.

Assuming that syntax is adopted as-is, you'd probably work with it as follows:

public enum class Result<T> {
    Success(T result),
    Error(Exception error)
}

Result<T> result = ...; // calculate some result here
if (result is Success(var value)) { ... }
else if (result is Error(var error)) { ... }

Is the pattern matching with generic types coming included with it?

That proposal won't be implemented for C# 7.0, which is more or less feature complete now. I expect that pattern matching will be expanded upon over several releases of the language, hopefully more point releases than new versions.

@gulshan Can you please show what kind of code the compiler would translate this into?

I keep seeing the title and thinking "ooh, genetic types, what's that?"

@gafter I'm not sure if this can be done with code generation. Now I realize there may be several steps for this proposal-

  • First, it's more about the pre-"Pattern Matching" is operator working with the bare generic types- instead of requiring them to specify type arguments. From my example, that will make result is Success a valid expression instead of requiring result is Success<int> or throwing Error CS0305.
  • Then this behavior should work with as operator, infering the type argument. result as Success should be infered to (or code generated to) result as Success<int> infering the int as the type argument.
  • Lastly, translating this concept naturally to pattern matching- making result is Success ok code generated to result is Success<int> ok.

@gulshan

The "bare" generic type for Success<int> would be Success<T> or Success<>, not Success. Success would be a completely different type.

// all legal and different types
public class Success { }
public class Success<T> { }
public class Success<T1, T2> { }

For the C# compiler to assume that Success meant Success<T> or Success<T1, T2> would lead to all kinds of ambiguity problems.

Then it can be Success<_> as stated at the end of my proposal, or Success<*>. But I really want it to be parameterless Success, if the ambiguity is somehow resolvable- like prioritizing types with less (or no) generic type parameters.

I keep seeing the title and thinking "ooh, genetic types, what's that?"

@jnm2 Genetic types are great for inheritance.

Was this page helpful?
0 / 5 - 0 ratings