Question

Say I define the following interface and class implementing it:

type IGreeter =
  abstract member GetGreeting: unit -> string

type Human =
  interface IGreeter with
    member this.GetGreeting () = "Why hello there"

Great. And say I have a list<Human> somewhere. Now, the problem is, how do I convert that to a list<IGreetable>? Example:

let humans: Human list = ...
let greeters: IGreeter = (upcast humans)

This gives both a warning and an error:

Warning FS0059: The type 'IGreeter list' does not have any proper subtypes and need not be used as the target of a static coercion

Error FS0193: Type constraint mismatch. The type Human list is not compatible with type IGreeter list The type 'IGreeter' does not match the type 'Human'

Was it helpful?

Solution

As the specification states, F# does not support generic variance:

14.5.2 Solving Subtype Constraints

Note: F# generic types do not support covariance or contravariance. That is, although single-dimensional array types in the CLI are effectively covariant, F# treats these types as invariant during constraint solving. Likewise, F# considers CLI delegate types as invariant and ignores any CLI variance type annotations on generic interface types and generic delegate types.

You'll have to cast the elements of the list and create a new one:

let greeters = humans |> List.map (fun h -> h :> IGreeter)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top