Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# multiple interface implementations with object expressions

Tags:

f#

According to docs you can implement multiple interfaces with object expressions. But if you see below code :


// Define two interfaces
type IFirst =
  abstract F : unit -> unit
  abstract G : unit -> unit

type ISecond =
  abstract H : unit -> unit
  abstract J : unit -> unit

// This object expression implements both interfaces.
let implementer : IFirst =
    { new ISecond with
        member this.H() = ()
        member this.J() = ()
      interface IFirst with
        member this.F() = ()
        member this.G() = () }

So casting to IFirst causes a compiler error. Why is that so?

like image 526
Onur Gumus Avatar asked Mar 31 '20 09:03

Onur Gumus


1 Answers

F# does not perform implicit conversions.

When type annotating in a let binding, the type must strictly match the expression. For example,

let value : obj = new System.Collections.Generic.List<int>()

will fail to compile, even though a List is very obviously an object.

When you write:

let implementer : IFirst = expr 

The type of expr must absolutely be IFirst. There's no implicit casting like in C#.

An object expression will have its type as the abstract type implemented, so:

{ new ISecond with ... }

will be inferred to have a type of ISecond. Combine it with no-implicit casts rule, and you have a compile error.

Because IFirst and ISecond are unrelated, you could (runtime) downcast to IFirst:

let firstImplementer = implementer :?> IFirst

Another option is to make a combined interface:

type IBoth = inherit IFirst inherit ISecond

and do:

let implementer =
    {
        new IBoth with ...

That way you can freely (static) upcast to IFirst or ISecond.

let firstImplementer = implementer :> IFirst
let secndImplementer = implementer :> ISecond
like image 183
Asti Avatar answered Nov 15 '22 08:11

Asti