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
В противном случае вы должны сделать небольшую апскейтинг, как описано в вашем примере.