F# and interface covariance: what to do? (specifically seq<> aka IEnumerable<>)

Unfortunately F# doesn;t support co\contravariance. That's why this

Seq.singleton "Hello World"  :> seq<obj> |> printEm 

doesn't work

You can declare parameter as seq<_>, or limit set of parameter types to some specific family by using flexible types (with hash #) this will fix this scenario:

let printEm (os: seq<_>) = 
for o in os do
    o.ToString() |> printfn "%s"

Seq.singleton "Hello World"  |> printEm 

Considering this lines:

Seq.singleton 42 :> seq<obj> |> printEm // error FS0193
Seq.singleton 42 :?> seq<obj> |> printEm

Variance only works for classes, so similar code will not work in C# too.

You can try casting sequence elements to required type explicity via Seq.cast


Use Seq.cast for this. For example:

Seq.singleton "Hello World"  |> Seq.cast |> printEm

Admittedly, this gives up type safety:

type Animal() = class end
type Dog() = inherit Animal()
type Beagle() = inherit Dog()

let printEm (os: seq<Dog>) =  
    for o in os do 
        o.ToString() |> printfn "%s" 

Seq.singleton (Beagle())  |> Seq.cast |> printEm // ok
Seq.singleton (Animal())  |> Seq.cast |> printEm // kaboom!

but it is expedient.

Alternatively, you can use flexible types:

type Animal() = class end
type Dog() = inherit Animal()
type Beagle() = inherit Dog()

let printEm (os: seq<#Dog>) =  // note #Dog
    for o in os do 
        o.ToString() |> printfn "%s" 

Seq.singleton (Beagle()) |> printEm // ok
Seq.singleton (Animal()) |> printEm // type error

which is just shorthand for the generic "forall types 'a when 'a :> Dog".

And finally, you can always map the upcast, e.g.

let printEm (os: seq<obj>) =  
    for o in os do 
        o.ToString() |> printfn "%s" 

Seq.singleton "Hello" |> Seq.map box |> printEm // ok

where box upcasts to obj.