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

Enable pattern matching on more specific types from type test patterns #1025

Closed
5 tasks done
Happypig375 opened this issue Jun 7, 2021 · 19 comments
Closed
5 tasks done

Comments

@Happypig375
Copy link
Contributor

Enable pattern matching on more specific types from type test patterns

I propose we allow:

type DU = DU of int * int
let (|Id|) = id
match box (1, 2) with
| :? (int * int) as (x, y) -> printfn $"A tuple: {x}, {y}"
| :? struct(int * int) as (x, y) -> printfn $"A struct tuple: {x}, {y}"
| :? DU as (DU (x, y)) -> printfn $"A DU: {x}, {y}"
| :? int as (Id i) -> printfn $"An int: {i}"
| _ -> printfn "Nope"

The existing way of approaching this problem in F# is to have an extra level of match expressions.

Pros and Cons

The advantages of making this adjustment to F# are

  1. Conciseness
  2. Convenience
  3. Composability

The disadvantage of making this adjustment to F# is that this makes inheritance-based code easier.

Extra information

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

Related suggestions: (put links to related suggestions here)

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.

@Happypig375
Copy link
Contributor Author

Related to #751 (comment)

@charlesroddie
Copy link

I don't think F# should add features to make type tests easier. They should not be part of the standard toolkit.

@Happypig375
Copy link
Contributor Author

I believe that this would complement #538 quite nicely. Now that direct type unions are allowed, we should be able to match on them more effectively.

@dsyme
Copy link
Collaborator

dsyme commented Jun 8, 2021

I don't think F# should add features to make type tests easier. They should not be part of the standard toolkit.

For me this is more about language uniformity. It's reasonable to make these things more orthogonal

@dsyme
Copy link
Collaborator

dsyme commented Jun 8, 2021

Indeed :? type as ident should always really have been :? type as pat

@Happypig375
Copy link
Contributor Author

Also there is the inconsistency that :? type as ident has the derived type for ident, but a & :? type as ident does not. An alternative route would be to fix & such that the correct type is inferred for &s after the type test, but I guess breaking changed are still not allowed.

@Happypig375
Copy link
Contributor Author

Draft RFC here: fsharp/fslang-design#595

@dsyme
Copy link
Collaborator

dsyme commented Jun 12, 2021

Thanks, marked as approved in principle

@chkn
Copy link

chkn commented Jun 21, 2021

| :? DU as (DU (x, y)) -> printfn $"A DU: {x}, {y}"

I'd love if this could just become

| DU (x, y) -> printfn $"A DU: {x}, {y}"

@Happypig375
Copy link
Contributor Author

@chkn The problem is with the change in type inference though.

let f = function DU (x, y) -> printfn $"A DU: {x}, {y}"

is inferred to be

val f : _arg1:DU -> unit

While changing to that would be

val f : _arg1:obj -> unit

With #968, you can use

let f = function :? DU (x, y) -> printfn $"A DU: {x}, {y}"

instead, which will have the correct type inference.

@dsyme
Copy link
Collaborator

dsyme commented Jun 21, 2021

I'd love if this could just become

When the input is an arbitrary object of type obj I believe we always want the :? type check cast to be explicit

@chkn
Copy link

chkn commented Jun 21, 2021

When the input is an arbitrary object of type obj I believe we always want the :? type check cast to be explicit

Fair enough- makes sense in this case.

But perhaps we could allow for an implicit type check when the input is already known to be an anonymous union containing the type suggested by the pattern?

@dsyme
Copy link
Collaborator

dsyme commented Jun 24, 2021

@auduchinok
Copy link

@dsyme The link points to 404.
I've seen it many times with other RFC links too.

@Happypig375
Copy link
Contributor Author

It's been moved to the preview folder.

@auduchinok
Copy link

Yes, I'm able to find it, thanks. The problem is many of the RFC links become 404 due to being moved. Maybe we could find an approach that would preserve the links somehow?

@dsyme
Copy link
Collaborator

dsyme commented Jun 24, 2021

Fixed thanks

Yes it's annoying but github doesn't give us any way, we'd have to publish a site

@smoothdeveloper
Copy link
Contributor

related or very close suggestion: #830

@dsyme
Copy link
Collaborator

dsyme commented Jun 9, 2022

Implemented in F# 6

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

6 participants