Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F#: Adding an interface (like IComparable) to an existing type (e.g. from a library like Fare)

Context: I'm using the .net/c#-library Fare in F# and I try to use e.g. Map.ofSeq. This fails as Fare.State does not support comparision since it does not implement the System.IComprable interface (FS0001).

In my naivity, I tried to add the interface IComparable like this:

type Fare.State with
    interface IComparable<Fare.State> with
        member this.CompareTo obj =
                               match box obj with
                               | :? Fare.State as other -> this.Id.CompareTo other.Id
                               | _ -> invalidArg "obj" "not a State"

This however is impossible as F# requires the implemented interfaces should be declared on the initial declaration of the type (FS0909).

I thought of the following works-arounds:

  1. Introducing a wrapper-type that includes a Fare.State as its only attribute and implements IComparable
  2. Storing the ID instead of the actual Fare.State and use a Map to translate to the actual state where needed
  3. Use some trick to add interface IComparable to the existing type.

If the third option is impossible, which option is most appropriate? Are there other options?

like image 210
fsharpnoob Avatar asked May 03 '16 13:05

fsharpnoob


1 Answers

While State type does implement (generic) IComparable<'T>, what F# looks for in comparison constraint is (non-generic) IComparable. The fact that the former is not a subtype of the latter seems like a lamentable design choice, but it's here to stay.

Your workarounds 1 and 2 make sense to me. From a design point of view, I would prefer a simple record wrapper around State. But if ids are unique, going with your other workaround is conceivable, if a bit clunky.

like image 121
scrwtp Avatar answered Sep 22 '22 10:09

scrwtp