[Proposal] Enhanced Pattern Matching Support for Either<T1, T2>-like Types in Lambdas and Switch Expressions #8415
Replies: 2 comments 2 replies
-
See: #113 Proper support for discriminated unions in general should obviate the need for special support for |
Beta Was this translation helpful? Give feedback.
-
Maybe an aside, could someone help clarify why the current C# type system does not support matching on types like My Either<T1, T2> Implementationpublic class Either<T1, T2>
{
private readonly T1? _left;
private readonly T2? _right;
private readonly bool _isLeft;
public Either(T1 value)
{
_left = value;
_isLeft = true;
}
public Either(T2 value)
{
_right = value;
_isLeft = false;
}
// Assign Either<TLeft, TRight> to the correct side when passed a value of type TLeft or TRight
public static implicit operator Either<T1, T2>(T1 value) => new (value);
public static implicit operator Either<T1, T2>(T2 value) => new (value);
// An attempt to get pattern matching to work with typeof(TLeft) or typeof(TRight)
/* This doesn't work */
public static implicit operator Type(Either<T1, T2> either) => either._isLeft ? typeof(T1) : typeof(T2);
// Using tuple deconstruction to get the values of the left and right sides
/* This sort of works */
public void Deconstruct(out T1? left, out T2? right)
{
left = _isLeft ? _left : default;
right = _isLeft ? default : _right;
}
} For example, here’s the kind of code I would like to work, but currently doesn't (even after overloading // Fake database call, always returns a new Person
Func<string, Either<Person, FrozenPerson>> GetOrCreatePerson = (name) => new(new Person(name, 30));
Either<Person, FrozenPerson> result = GetOrCreatePerson("Doe, John");
bool updateDB = result switch
{
typeof(Person) => true,
typeof(FrozenPerson) => false,
};
Console.WriteLine($"Do we need to update the database? {(updateDB ? "Yes" : "No")}"); Currently, I can achieve something close to this by using a // Fake database call, always returns a new Person
Func<string, Either<Person, FrozenPerson>> GetOrCreatePerson = (name) => new(new Person(name, 30));
Either<Person, FrozenPerson> result = GetOrCreatePerson("Doe, John");
bool updateDB = result switch
{
(Person, null) => true,
(null, FrozenPerson) => false,
_ => throw new Exception("Shouldn't need this; Either always has one non-null value")
};
Console.WriteLine($"Do we need to update the database? {(updateDB ? "Yes" : "No")}"); But ultimately just using |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Overview:
Currently, C# provides powerful pattern matching features, such as
switch
expressions and pattern matching with types. However, there are limitations when working with types likeEither<T1, T2>
or other functional-style constructs, especially in lambdas and when dealing with static typing. This feature request proposes extending C#'s pattern matching capabilities to allow explicit type matching within lambda expressions and switch expressions, improving readability and functionality.Motivation:
In many functional programming scenarios, we work with constructs like
Either<T1, T2>
,Result<TSuccess, TFailure>
, or similar types that encapsulate different possible values. While C# allows us to use pattern matching in switch expressions or explicitly handle cases in methods, it lacks the flexibility to express type-based matching directly in lambda expressions or switch expressions.Currently, developers must rely on indirect solutions like checking the type manually inside lambdas or using explicit "left" and "right" patterns, which reduce readability and clarity. This creates confusion and increases cognitive overhead, especially when reviewing code that uses functional-style methods such as
Match
for handling multiple types.Proposal:
Allow Type Patterns in Lambda Expressions
Extend the lambda syntax to support type patterns directly in the lambda parameters. This would make it possible to match on the types encapsulated in constructs like
Either<T1, T2>
without requiring additional method calls or verboseif
statements.Example Syntax:
Explanation:
Func<T1, TResult>
andFunc<T2, TResult>
signatures to implicitly understand the types being handled.Extend switch Expressions to Handle Type-Based Matching for Functional Constructs
Extend the existing
switch
expression to natively handle type matching for constructs likeEither<T1, T2>
and other functional types without requiring explicit boolean checks.Example Syntax:
Explanation:
switch
expression to match on the static types of the encapsulated values (Person and FrozenPerson) without needing to unpack or type-check manually.Either<T1, T2>
, improving clarity and reducing the need for intermediate variable extraction or explicit type checking.Rationale:
Either<T1, T2>
would become more expressive and easier to read. The explicit type-based matching in lambdas and switch expressions would eliminate ambiguity regarding which types are being handled, making code easier to reason about.IsLeft
/IsRight
flags inEither
-like types. Enabling type patterns in lambdas andswitch
expressions would streamline such code, removing unnecessary complexity.switch
expressions, but the lack of similar support in lambdas and certain constructs leads to inconsistencies. By allowing type patterns in these contexts, C# would align better with functional programming paradigms.Conclusion:
This feature request aims to extend C#'s pattern matching capabilities to improve handling of
Either<T1, T2>
-like constructs in lambdas and switch expressions. These changes would enhance readability, reduce boilerplate code, and make the language more flexible and consistent when working with functional programming paradigms.Beta Was this translation helpful? Give feedback.
All reactions