Consider I have two different library types:
type Foo = { foo : string }
type Bar = { bar : int32 }
I want to implement generic function zoo
that will work for either Foo
or Bar
instances. And I cannot change Foo
and Bar
because they are part of library code.
Here's my first attempt using type extensions and inline function as explained here:
// Library.fs
module Library
type Foo = { foo : string }
type Bar = { bar : int32 }
// Program.fs
type Foo with
static member zoo (f : Foo) = "foo"
type Bar with
static member zoo (b : Bar) = "bar"
let inline zoo (x : ^t) =
(^t : (static member zoo : ^t -> string) x)
let f = zoo { foo = "1" } // error FS0001: The type 'Foo' does not support the operator 'zoo'
Why don't inline function definition relies on type extensions? How could I solve my problem without changing of the initial Foo
and Bar
type definitions?
Use method overload.
The problem with extension methods is that they are not taken into account when solving member constraints .
So you can use method overload, as shown already in your own answer or you can go further and create an inline generic function by using an intermediate type and an intermediate method (in this case an operator for simplicity) to do the trick:
type T = T with
static member ($) (T, x:Foo) = "foo"
static member ($) (T, x:Bar) = "bar"
let inline zoo x = T $ x
let f = zoo { foo = "1" }
Here you have more details about how this works.
Be aware that this function will be inlined, so for instance you won't be able to call it from C#, if this is required don't use a function, use simple and standard method overload.
The best thing I could get so far is
type Ext =
static member zoo (f : Foo) = "foo"
static member zoo (b : Bar) = "bar"
let f = Ext.zoo { foo = "1" } // "foo"
let b = Ext.zoo { bar = 2 } // "bar"
It is not the best and not very generic solution but at least it works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With