Skip to content

Instantly share code, notes, and snippets.

@isaacabraham
Last active November 8, 2020 21:18
Show Gist options
  • Select an option

  • Save isaacabraham/a184e2a3f97f607ca965e7a71abb64dd to your computer and use it in GitHub Desktop.

Select an option

Save isaacabraham/a184e2a3f97f607ca965e7a71abb64dd to your computer and use it in GitHub Desktop.
// Couple of interfaces
type IFoo = interface end
type IBar = interface end
// Some records that implement the interfaces
type FooImpl1 = { Name : string } interface IFoo
type FooImpl2 = { OtherName : string } interface IFoo
type BarImpl1 = { Age : int } interface IBar
// Some example lists of data
let listOfFooImpl1s = [ { Name = "Isaac" }; { Name = "Blah" } ]
let listOfFoos1 : IFoo list = [ { Name = "Isaac" }; { Name = "Blah" } ] // Works
let listOfFoos2 : IFoo list = [ { Name = "Isaac" }; { OtherName = "Blah" } ] // Even this works
let listOfBars : IBar list = [ { Age = 21 } ]
let listOfFoosBad1 = [ { Name = "Isaac" } :> IFoo; { OtherName = "Blah" } ] // This doesn't work
let listOfFoosBad2 = [ { Name = "Isaac" } :> IFoo; { OtherName = "Blah" } :> _ ] // This works but is too verbose
let listOfFoosBad3 : IFoo list = [ "Isaac"; "Blah" ] |> List.map(fun x -> { Name = x }) // This doesn't work!
// A class that "consumes" IFoos and IBars
type Runner =
static member Go(foo:IFoo) = printfn "A foo!"
static member Go(foo:IFoo list) = printfn "A list of foo!"
static member Go(foo:IBar) = printfn "A bar!"
static member Go(foo:IBar list) = printfn "A list of bar!"
Runner.Go listOfFoos1
Runner.Go listOfFoos2
Runner.Go listOfBars
Runner.Go listOfFooImpl1s // This doesn't work. I want this to automatically resolve to IFoo list.
// A class that implements the IFoo version as a flexible type.
type SmartRunner =
static member Go(foo:IFoo) = printfn "A foo!"
static member Go(foo:#IFoo list) = printfn "A list of foo!"
static member Go(foo:IBar) = printfn "A bar!"
static member Go(foo:IBar list) = printfn "A list of bar!"
SmartRunner.Go listOfFoos1
SmartRunner.Go listOfFoos2
SmartRunner.Go listOfBars
SmartRunner.Go listOfFooImpl1s // Works! However, the signature of that Go method has now changed to be "any 'a that implements IFoo as a constraint". The constraint is also not shown in all tooling, reducing readability.
SmartRunner.Go [ { Name = "Isaac" }; { OtherName = "Blah" } ] // This unfortunately doesn't work
// However, what if we want to also make the IBar list version flexible?
type SmarterRunner =
static member Go(foo:IFoo) = printfn "A foo!"
static member Go(foo:#IFoo list) = printfn "A list of foo!"
static member Go(foo:IBar) = printfn "A bar!"
static member Go(foo:#IBar list) = printfn "A list of bar!" // doesn't compile - the second overload and this one have the same signature.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment