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 upcasting in pattern match expressions #536

Closed
5 of 6 tasks
chkn opened this issue Feb 11, 2017 · 2 comments
Closed
5 of 6 tasks

Allow upcasting in pattern match expressions #536

chkn opened this issue Feb 11, 2017 · 2 comments

Comments

@chkn
Copy link

chkn commented Feb 11, 2017

Allow upcasting in pattern match expressions

I propose we enable some syntax to upcast a bound identifier in a pattern matching expression.

Consider this simple example:

type Base() = member __.SomeBaseMember = "hello"
type Foo() = inherit Base()
type Bar() = inherit Base()
type DU =
   | FOO of Foo
   | BAR of Bar
let foo = FOO(Foo())
match foo with
| FOO(b)
| BAR(b) -> b.SomeBaseMember

As expected, this code yields a message like:

This expression was expected to have type
     'Foo'    
 but here has type
     'Base'     at 5,6

I propose we add an upcast syntax so you can write something like:

match foo with
| FOO(b :> Base)
| BAR(b :> Base) -> b.SomeBaseMember

In the pattern match body, the identifier b would then be typed Base.

Alternatives

  1. Make no changes to the language and instead structure your code like this:

    match foo with
    | FOO(b) -> b.SomeBaseMember
    | BAR(b) -> b.SomeBaseMember

    This works, but when there are many cases, or when b.SomeBaseMember is actually a complex expression, this becomes less than ideal.

    A better workaround is to declare an active pattern:

    let inline (|Base|) b = b :> Base
    match foo with
     | FOO(Base b) 
     | BAR(Base b) -> b

    However, this is still not as elegant as an upcast operator built into the pattern matching language.

  2. Instead of adding new syntax, use the current type check pattern:

    match foo with
    | FOO(:? Base as b)
    | BAR(:? Base as b) -> b.SomeBaseMember

    This currently produces a compiler error:

Type constraint mismatch. The type 
     'Base'    
is not compatible with type
     'Foo'    
at 5,6

Pros and Cons

Pro: A more elegant syntax to solve the problem above.

Con: Requires implementation in the compiler

Extra informtion

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

Affadavit (must be submitted)

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 would be willing to help implement and/or test this
  • I or my company would be willing to help crowdfund F# Software Foundation members to work on this
@smoothdeveloper
Copy link
Contributor

It is a nicely written suggestions and I like the idea of extending abilities in pattern matching.

That being said, I'm trying to see if F# couldn't be made super clever in such case by doing that unified binding automatically, so it wouldn't even require the cast in this case (but the proposed syntax could be supported as well for defining the type explicitly).

It would work by identifying the most specialized common subtype that can unify the bindings.

I think having the unification work without extra syntax would be very nice and keep that feature approachable to the newcomers.

@dsyme
Copy link
Collaborator

dsyme commented Jan 9, 2023

I get the proposal, which I haven't commented on before. But it is just too specific and rare to be needed in the core language. The active pattern workaround looks OK to me

@dsyme dsyme closed this as completed Jan 9, 2023
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

3 participants