I suggest we ...

Make .Tag and .Is* discriminated union properties visible from F#

The .NET class that encodes a discriminated union has `.Is* : bool` properties, for example this:

type Foo = A | B

has the following:

member IsA : bool
member IsB : bool

They are hidden from F#, but they could actually be quite useful. I regularly find myself writing something like this:

List.filter (function A -> true | _ -> false)

when I could write:

List.filter (fun x -> x.IsA)

15 votes
Vote
Sign in
(thinking…)
Password icon
Signed in as (Sign out)
You have left! (?) (thinking…)
Loic Denuziere shared this idea  ·   ·  Flag idea as inappropriate…  ·  Admin →

This proposal is “approved in principle” for F# 4.0+. It would make a good addition to F#. (I don’t think the loss of purity (e.g. wr.t. ordering of union cases) is a critical problem and I believe you can turn of the DefaultAugmentation in any case)

Some technical issues may need to be ironed out during implementation.

If this is done, the Tag properties present on these types should also be revealed, that is covered by a separate item.

An implementation and testing would need to be provided by someone in the F# community (possibly including Microsoft or Microsoft Research, though not limited to them).

Implementations of approved language design can now be submitted as pull requests to the appropriate branch of http://github.com/Microsoft/visualfsharp. See http://fsharp.github.io/2014/06/18/fsharp-contributions.html for information on contributing to the F# language and core library..

I’d be glad to help guide people through the implementation process.

If you strongly think this should not be approved please chime in with your technical feedback.

Thanks
Don Syme, F# Language and Core Library Evolution

5 comments

Sign in
(thinking…)
Password icon
Signed in as (Sign out)
Submitting...
  • Christopher Atkins commented  ·   ·  Flag as inappropriate

    There are a few considerations to take into account when tackling this, per Don Syme:

    * The problem is that the generated “Is*” and “New*” for unions are inserted very late in the compilation pipeline, in the “ILX” phase, using nasty code that is somewhat ancient. There are lots of corresponding cases in tc.fs and check.fs to check that the user doesn’t define these him/herself.

    * The whole generation of these should probably be lifted up to happen during type checking (the same time we generate compare/equality methods, for example, see augment.fs). Then the “check for duplicates” core would be irrelevant.


    * The messiness is compounded by the fact that there are special cases in ILX generation for lists, options and AllowNullValueAsRepresentation unions.

  • Robert Jeppesen commented  ·   ·  Flag as inappropriate

    I agree with Peter, it would be nice to have this as part of the static type.
    We should have both: The static `IsA` would call the instance `IsA`.

  • Loic Denuziere commented  ·   ·  Flag as inappropriate

    Peter: The thing is, these methods already exist as instance methods, they're just not exposed in F#. Making them static would break backward compatibility for C# code that uses them.

    There is a discussion about a static syntax for instance methods here: http://fslang.uservoice.com/forums/245727-f-language/suggestions/5663326-syntax-for-turning-properties-into-functions which would provide the same advantages as you cite, but for all instance methods.

  • Peter Strøiman commented  ·   ·  Flag as inappropriate

    Or even better, have it exposed as static members, so you can write
    List.filter Foo.IsA

    The latter can work better with some cases of type inference, e.g.
    let get<'T> () = instance :?> 'T // instance is declared as an obj

    In that case
    get () |> List.filter Foo.IsA
    Would automatically type infer 'T to be List<Foo>, where
    get () |> List.filter (x -> x.IsA)
    would not, and thus would not compile

F# Language

Feedback and Knowledge Base