FSharp и upcasting для интерфейсов кажется избыточным

У меня есть следующий фрагмент кода с использованием реактивных расширений:

    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
    )

Это работает. Однако, если я отбрасываю upcast до IDisposable, то код не компилируется, ссылаясь на неоднозначные перегрузки. Однако CompositeDisposable является IDisposable. Почему механизм вывода типов не может решить эту проблему? Заметьте, я использую этот шаблон почти все время в C#, возвращая CompositeDisposable из Observable.Create без необходимости выгрузки.

1 ответ

Решение

Как сказал @kvb, функции не поддерживают дисперсию, поэтому для интерфейсов и подклассов требуется upcast.

Вот небольшой пример, демонстрирующий поведение с подклассами:

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

Если функция f написано вами, добавление ограничений типа может помочь:

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

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

В противном случае вы должны сделать небольшую апскейтинг, как описано в вашем примере.

Другие вопросы по тегам