Intellenum icon indicating copy to clipboard operation
Intellenum copied to clipboard

Match/Switch methods on members

Open jupjohn opened this issue 10 months ago • 1 comments

Describe the feature

Mentioned as an alternative to the implemented solution under #125, I believe that Dunet-like Match/Switch methods would be a good addition as, opposed to C#'s switch expression/statements on the underlying value, it allows for compile-time guarantees that all members are explicitly handled.

I don't believe it's necessary to have the "this-member-or-else" matching that a library like Dunet has (i.e. MatchMyMember(Func<Union.MyMember, T> matched, Func<T> @else) as expecting specific members can still be done with simple x == MyEnum.MyMemberValue checks. Perhaps having the ability to pass in a state object to reduce/prevent closure allocations would be nice (see Dunet's stateful matching.)

Rough idea of how I see this looking (for Match)

[Intellenum<int>]
[Member("Motorbike", 1)]
[Member("ATV", 2)]
[Member("Reliant Robin", 3)]
public partial class VehicleType;

// Source-gen stubs
public TReturn Match<TReturn>(
    Func<VehicleType, TReturn> matchMotorbike,
    Func<VehicleType, TReturn> matchAtv,
    Func<VehicleType, TReturn> matchReliantRobin
);

public void Switch(  // SwitchAsync would also be nice
    Action<VehicleType> matchMotorbike,
    Action<VehicleType> matchAtv,
    Action<VehicleType> matchReliantRobin
);

// Usage
var vehicleType = VehicleType.ReliantRobin;

var wheelCount = vehicleType.Match(
    motorbike => 2,
    atv => 4,
    reliantRobin => 3
);

// "Vehicle "Reliant Robin" has 3 wheels"
Console.WriteLine($"Vehicle \"{vehicleType.Name}\" has {wheelCount} wheels.")

Potential issues

An issue I can foresee with this (which is also an issue in Dunet, but less due to type safety) is when the order of the enum's members is changed, the Match method will still be correct from a compiler's perspective, but the matched function may be different unless you explicitly specified parameter names. Sounds like a nasty thing to encounter in the real world.

The only way I see to get around this is to go fully down the discriminated union path and give members distinct types OR only type them as parameters to Match/Switch.

jupjohn avatar Jun 08 '25 01:06 jupjohn

Something similar is present in OneOf library https://github.com/mcintyre321/OneOf/blob/6e02dbe75d0f20f198c640d4c04190a85c5ac9e6/OneOf/OneOfBaseT1.generated.cs#L47

gritcsenko avatar Aug 11 '25 17:08 gritcsenko