Reputation: 769
I cannot find a way of implementing an interface with an object expression when it contains a method with no types that can refer to the type for which the implementation is being put into place. A method with signature unit -> string
is a simple example. Example code below:
type AsString =
abstract member asString: unit -> string
type AsString2<'T> =
abstract member asString: 'T -> string
type SomeDu =
| A of int
| B of string
| C of float
interface AsString
with member self.asString () =
match self with
| A a -> string a
| B b -> b
| C c -> string c
interface AsString2<SomeDu>
with member self.asString x =
if not (x = self) then failwith "argument must be the member container"
match self with
| A a -> string a
| B b -> b
| C c -> string c
//this expression was expected to have type AsString but here has type SomeDU
let implSomeDU =
{new AsString with
member self.asString () =
match self with
| A a -> string a
| B b -> b
| C c -> string c}
If I attempt to refer to the implementing type as I've done with AsString2
then no problem with object expressions, but the implementation on the DU now has a requirement that I cannot express in the type system: the argument has to be the DU instance or the method has no value.
Is there any trick that'd let me implement AsString
as an object expression for SomeDu?
Upvotes: 0
Views: 293
Reputation: 243041
When implementing an interface using an object expression, the type of this
is always going to be the interface and nothing else - unlike when implementing an interface in some other type (where this
refers to the current value), in case of object expressions, the "current value" is just the interface implementation.
If you want to implement an interface in an existing type, do that by implementing it in the type itself.
If you want to get an implementation of an interface based on some other value, you can write a function that takes the value and implements the interface using object expression.
In your case, your function in the second case would look like this:
type AsString =
abstract member asString: unit -> string
type SomeDu =
| A of int
| B of string
| C of float
let implSomeDU someDu =
{ new AsString with
member self.asString () =
match someDu with
| A a -> string a
| B b -> b
| C c -> string c }
Upvotes: 3