fsharp / fslang-suggestions

The place to make suggestions, discuss and vote on F# language and core library features
346 stars 21 forks source link

Allow returning `int` from active patterns that only classing the input #1344

Open Tangent-90 opened 9 months ago

Tangent-90 commented 9 months ago

I propose we allow returning int from active patterns that only classing the input, instead of Choice<unit, unit, ..., unit>, for better performance

Sample:

// Marking the return type as `int`
// only allow returning the cases defined by the name of the active pattern, no explicit numbers like 1, 2, 3, ...
let (|XmlDoc|SingleLine|Else|) (line: string): int =
    if line.StartsWith("///") then XmlDoc
    elif line.StartsWith("//") then SingleLine
    else Else

// Marking the return type of (|A|B|C|) as `int`
let f ((|A|B|C|) : _ -> int) = 
    match "some thing" with
    | A -> "A"
    | B -> "B"
    | C -> "C"

For a n-cases active pattern, its int representation will be:

The existing way of approaching this problem in F# is returning Choice<unit, unit, ..., unit> from those active patterns.

Pros and Cons

The advantages of making this adjustment to F# are

The disadvantages of making this adjustment to F# are ...

Extra information

Estimated cost (XS, S, M, L, XL, XXL): M

Related suggestions: (put links to related suggestions here)

1041

612

Affidavit (please submit!)

Please tick these items by placing a cross in the box:

Please tick all that apply:

For Readers

If you would like to see this issue implemented, please click the :+1: emoji on this issue. These counts are used to generally order the suggestions by engagement.

Happypig375 commented 9 months ago

The original suggestion of https://github.com/fsharp/fslang-suggestions/issues/612 included struct total active patterns which was not implemented.

// Marking the return type as `int`
// only allow returning the cases defined by the name of the active pattern, no explicit numbers like 1, 2, 3, ...
let [<return: Struct>] (|XmlDoc|SingleLine|Else|) (line: string) =
    if line.StartsWith("///") then XmlDoc
    elif line.StartsWith("//") then SingleLine
    else Else
error FS3385: The use of '[<Struct>]' on values, functions and methods is only allowed on partial active pattern definitions

In the implementation PR (https://github.com/dotnet/fsharp/pull/10338), the original message had this "Not sure what's the value counterpart for Choice?" which was ignored in the whole thread later. ValueChoices might be usable but I am not sure if the .NET Runtime can merge generic fields of the same type into the same field for the same memory efficiency as int.

cartermp commented 9 months ago

I think a disadvantage to call out is that to make this non-breaking, it would require the type annotation, which would make it much less likely to be used. That said, I would prefer a more efficient representation by default, and I think the impact of breaking changes is likely fairly low if we were to change it from a FSharpChoice<Unit, Unit, ..., Unit> to an int under the covers.

Tangent-90 commented 9 months ago

Maybe it is not suitable to pass these kind of active pattern by parameters like let f ((|A|B|C|) : _ -> int) = ..., because the active pattern function may return any integers that not match to the labels...

Or maybe we can add a wildcard case to it, making it to be a multiple cases partial active pattern (|A|B|C|_|): _ -> int?