Search code examples
c#.netf#functional-programmingclr

How to make Array Covariance work in F#


From Array Covariance article:

Arrays where the element type is a reference type are covariant. [...] It was added to the CLR because Java requires it and the CLR designers wanted to be able to support Java-like languages.

Array covariance is supported in CLR, but how can I use this convenient feature in F#?

type Foo () = class end
type Bar () = inherit Foo ()

// must have type Foo []
let foo : Foo [] = Array.create 1 (Bar ())
                                // ^^^^^^ must not cast to Foo
// must throw ArrayTypeMismatchException
foo.[0] <- Foo ()

In the example, I'd like to have foo store a Bar array behind the scene, just as implemented in CLR.


Solution

  • In many places where C# allows implicit casting between types, F# requires explicit casts.

    The F# compiler will not even allow a direct cast from Bar[] to Foo[] (The type 'Bar []' does not have any proper subtypes and cannot be used as the source of a type test or runtime coercion.), you need to cast to object first.

    let foo =  Array.create 1 (Bar ()) :> obj :?> Foo[]
    

    By the way, I would not call array covariance a convenient feature, it causes more problems than it solves.