Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why aren't IDictionary<_, > keys compatible with derived types?

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?

like image 831
MiloDC Avatar asked Apr 17 '26 07:04

MiloDC


1 Answers

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.

like image 140
TheInnerLight Avatar answered Apr 19 '26 18:04

TheInnerLight