type TypeA () = class end
type TypeB () = inherit TypeA ()
// "The type 'TypeA' does not match the type 'TypeB'":
let iDict : IDictionary<TypeA, bool> = [ TypeB (), true; TypeB (), false ] |> dict
let d = Dictionary<TypeA, bool> ()
// This is OK, though:
d.Add (TypeB (), false)
Why are IDictionary keys incompatible with derived types?
Let's look at the differences between the two approaches:
In the first case, you are creating a list:
[ TypeB (), true; TypeB (), false ]
This has type (TypeB * bool) list.
The dict function has type seq<'Key * 'Value> -> IDictionary<'Key,'Value> (requires equality).
Consequently, applying the dict function
dict [ TypeB (), true; TypeB (), false ]
results in a value of type IDictionary<TypeB, bool>.
IDictionary<TypeB, bool> is not equivalent to IDictionary<TypeA, bool>, these are completely different and incompatible types, hence the compiler error.
If you wanted to initialise your dictionary from a collection of more derived types in this way, you'd have to do the upcast explicitly, e.g.:
let iDict =
[ TypeB (), true; TypeB (), false ]
|> List.map (fun (a,b) -> (a :> TypeA), b)
|> dict
In your second example, this problem never materialised because you originally created a Dictionary<TypeA, bool>.
You then use the Add method to add something of TypeB to the dictionary. Since Add is a method, F# can perform automatic upcasting on the argument, such that your value of TypeB is upcast to TypeA automatically.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With