Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow returning bool instead of unit option for partial active patterns #1041

Closed
5 tasks done
Tarmil opened this issue Jul 5, 2021 · 10 comments
Closed
5 tasks done

Comments

@Tarmil
Copy link

Tarmil commented Jul 5, 2021

Allow returning bool instead of unit option for partial active patterns

I propose we allow returning bool from partial active patterns that don't return a significant value apart from "matches" / "doesn't match".

The existing way of approaching this problem in F# is to return Some () if the value matches and None if it doesn't.

For example the active pattern for the following:

match key with
| CaseInsensitive "foo" -> ...
| CaseInsensitive "bar" -> ...

would currently be written as:

let (|CaseInsensitive|_|) (pattern: string) (value: string) =
    if String.Equals(value, pattern, StringComparison.OrdinalIgnoreCase) then
        Some ()
    else
        None

With this proposal, it could be written as:

let (|CaseInsensitive|_|) (pattern: string) (value: string) =
    String.Equals(value, pattern, StringComparison.OrdinalIgnoreCase)

Pros and Cons

The advantages of making this adjustment to F# are

  • A simpler way to write active patterns that just check a condition without returning a value.
  • Fewer memory allocations and probably better generated IL.

The disadvantages of making this adjustment to F# are

  • Adding one more way to do the same thing.

Extra information

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

Related suggestions:

Affidavit (please submit!)

Please tick this by placing a cross in the box:

  • This is not a question (e.g. like one you might ask on stackoverflow) and I have searched stackoverflow for discussions of this issue
  • I have searched both open and closed suggestions on this site and believe this is not a duplicate
  • This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it.

Please tick all that apply:

  • This is not a breaking change to the F# language design
  • I or my company would be willing to help implement and/or test this

For Readers

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

@kevmal
Copy link

kevmal commented Jul 5, 2021

I have often found myself wanting this.

@dsyme
Copy link
Collaborator

dsyme commented Jul 5, 2021

One of the problems is we assert an option return type early in type inference, and use it as the known type for checking the right hand side.

It might be technically possible to make this work:

let (|CaseInsensitive|_|) (pattern: string) (value: string) : bool =
    String.Equals(value, pattern, StringComparison.OrdinalIgnoreCase)

or of course we could use an attribute.

@dsyme
Copy link
Collaborator

dsyme commented Jul 5, 2021

I'll marked this as approved in principle, it's pretty reasonable to want this.

@Happypig375
Copy link
Contributor

Struct active patterns right now require [<return: Struct>] which is just not ergonomic. Since this request to allow returning bool is exactly for ergonomic reasons, can we just return a bool without an extra attribute? For consistency, we can consider allowing dropping the attribute for ValueOption too.

@dsyme
Copy link
Collaborator

dsyme commented Oct 16, 2021

. Since this request to allow returning bool is exactly for ergonomic reasons, can we just return a bool without an extra attribute?

In principle I'd like to, and I'd like to see this prototyped for both cases. In general it's actually not backwards compatible strictly, since without the option type is inferred from the (|ABC|_|) before the rest of the definition is processed. That said, I'm sure we can enable this is there is an explicit return type.

@auduchinok
Copy link

auduchinok commented Oct 16, 2021

@dsyme Assuming we could have anonymous union types in future, would initially inferring something like 'T option | bool and sticking to one of the types later help here?

@Happypig375
Copy link
Contributor

@auduchinok Existing implementations may be broken if another type than option is used for inference, like when the body only contains calls to generic functions. Instead, we could modify type checking and default to option if bool or voption are not inferred from the result.

@kerams
Copy link

kerams commented Feb 3, 2023

If we go down the : bool route, wouldn't it make sense to also allow : unit voption for partial patterns as an alternative to [<return: Struct>]? Granted, let (|A|_|) x : unit voption = ValueSome A looks weird because A can also be returned, but the Option equivalent works.

Since this request to allow returning bool is exactly for ergonomic reasons, can we just return a bool without an extra attribute

I've just had a look at this, and, as was mentioned elsewhere, the current ordering of type checking operations does make it non-trivial. My first impression of the annotation solution was that it should be fairly easy to implement.

@edgarfgp
Copy link
Member

@vzarytovskii I think this can be closed ? dotnet/fsharp#16473

@vzarytovskii
Copy link

@vzarytovskii I think this can be closed ? dotnet/fsharp#16473

Yeah, thanks, I was waiting until insertion is done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants