Skip to content

Instantly share code, notes, and snippets.

@dmitry-a-morozov
Last active August 29, 2015 14:24
Show Gist options
  • Save dmitry-a-morozov/874d65a88d6bee6abaa7 to your computer and use it in GitHub Desktop.
Save dmitry-a-morozov/874d65a88d6bee6abaa7 to your computer and use it in GitHub Desktop.
object expression with interface chain
type IOOP = abstract Mutate: unit -> unit
type IFunctional<'T> = abstract Reduce: 'T list * ('T -> 'T -> 'T) -> 'T
type ProgramThatMatters =
static member Run<'T, 'a when 'a :> IOOP and 'a :> IFunctional<'T>>(paradigm: 'a) = ()
let myCode = {
new IFunctional<int> with
member __.Reduce(xs, f) = List.reduce f xs
interface IOOP with
member __.Mutate() = ()
}
ProgramThatMatters.Run myCode
//fails to compile with
// Error 1 The type 'IFunctional<int>' is not compatible with the type 'IOOP' ...
@latkin
Copy link

latkin commented Jul 2, 2015

Workaround:

type ICombine<'T> =
    inherit IOOP
    inherit IFunctional<'T>

let myCode = {
    new ICombine<int>
    interface IFunctional<int> with
        member __.Reduce(xs, f) = List.reduce f xs 
    interface IOOP with
        member __.Mutate() = ()
}

Spec (section 6.3.8):

let obj4 =
    { new System.Object() with
        member x.Finalize() = printfn "Finalize";
      interface System.IDisposable with
        member x.Dispose() = printfn "Dispose"; }

An object expression can specify additional interfaces beyond those required to fulfill the abstract slots of the type being implemented. For example, obj4 in the preceding examples has static type System.Object but the object additionally implements the interface System.IDisposable. The additional interfaces are not part of the static type of the overall expression, but can be revealed through type tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment