In my code I have a scenario where I'd like F# to automatically upcast values of one function type (e.g.
IBase -> unit) to another, explicitly specified function type (
IDerived -> unit). While this seems to be generally supported, I found cases where it fails for no obvious reason.
In the code below,
case8 seem equivalent to me: In each case, there's an expression of type
IBase -> unit on the right hand side that is bound to a name of type
IDerived -> unit. So why are cases 4, 5 and 7 not allowed?
type IBase = interface end type IDerived = inherit IBase let foo (x: IBase) = () let bar = fun (x: IBase) -> () type T = T with static member (!!) (_: T) = foo let baz = !!T let case1: IDerived -> unit = foo // OK let case2: IDerived -> unit = bar // OK let case3: IDerived -> unit = baz // OK let case4: IDerived -> unit = !!T // Expecting 'IDerived -> unit' but given 'IBase -> unit' let case5: IDerived -> unit = upcast !!T // Type 'IBase -> unit' is not compatible with type 'IDerived -> unit' let case6: IDerived -> unit = let z = !!T in z // OK let case7: IDerived -> unit = fun (x: IBase) -> () // Expected x to have type 'IDerived' but here has type 'IBase' let case8: IDerived -> unit = let z = fun (x: IBase) -> () in z // OK
EDIT: To clarify, I'm mostly wondering why the 8 cases are not treated equally by the compiler. For example, I'd expect the binding
let z... in
case8 to be superfluous, yet it makes a difference (compared to
EDIT: Here's some code to demonstrate what I'm trying to achieve: https://dotnetfiddle.net/AlpdpO It also contains a solution/workaround, so I'm really asking more for technical details/reasons rather than alternative approaches. I thought about raising an issue on GitHub already, but feel like the issue is most likely just a misunderstanding on my side.