Question

I have the following code snippet using the reactive extensions:

    let value : 't = ...

    Observable.Create<'t>(fun observer ->
        let subject = new BehaviorSubject<'t>(value)
        let d0 = subject.Subscribe(observer)
        let d1 = observable.Subscribe(subject)
        new CompositeDisposable(d0, d1) :> IDisposable
    )

This works. However if I drop the upcast to IDisposable then the code fails to compile, citing ambiguous overloads. However CompositeDisposable is an IDisposable. Why is the type inference engine failing to resolve this? Note I use this pattern almost all the time in C# returning CompositeDisposable from Observable.Create without having to upcast.

Was it helpful?

Solution

As @kvb said, functions don't support variance so upcast is required for interfaces and subclasses.

Here is a small example demonstrating the behavior with subclasses:

type A() =
    member x.A = "A"

type B() =
    inherit A()
    member x.B = "B"

let f (g: _ -> A) = g()

let a = f (fun () -> A()) // works
let b = f (fun () -> B()) // fails

If function f is written by you, adding type constraints could help:

// This works for interface as well
let f (g: _ -> #A) = g()

let a = f (fun () -> A()) // works
let b = f (fun () -> B()) // works

Otherwise, you have to do a litle upcast as your example described.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top