简体   繁体   中英

Why does F# map implement the interfaces with mutable operations?

I was somewhat surprised when I realised that F#'s map implements both IDictionary<'Key, 'Value> and ICollection<KeyValuePair<'a, 'b>> considering that both supports mutation (add and remove) as part of the contract.

Looking at the implementation of map it simply excepts when you try to cause mutation!

let map = [| (1, "one"); (2, "two") |] |> Map.ofArray
let dict = map :> IDictionary<int, string>
dict.Add(3, "three");;

the above code throws the exception:

System.NotSupportedException: Map values cannot be mutated. at Microsoft.FSharp.Collections.FSharpMap 2.System-Collections-Generic-IDictionary 2-Add(TKey k, TValue v) at .$FSI_0007.main@() Stopped due to error

which is as expected.

For an immutable collection to be able to expose itself as a mutable one only for it to throw exception when the consumer of that collection tries to cause mutation seems such a dangerous decision.

Am I missing something here?

I think the main reason is that .NET does not have any interface that represents immutable (part of an interface of a) dictionary. This means that all .NET APIs have to take IDictionary<K, V> as parameter, even if they only intend to read from the dictionary. So:

  • Implementing IDictionary<'K, 'V> is pretty much the only way to make the F# immutable map usable as a parameter to any .NET libraries that need an object that supports lookup. Sadly, there is no read-only alternative in .NET.

  • Implementing ICollection<KeyValuePair<'K, 'V>> does not make too much sense to me, because there is a read-only alternative IEnumerable<KeyValuePair<'K, 'V>> and immutable map implements this interface too.

    But perhaps there are some .NET libraries that take ICollection<'T> (for efficientcy - ie to get Count without enumerating all elements) and use it in a read-only way.

    EDIT: As noted by Daniel in the comment, implementing ICollection is required, because the IDictionary interface inherits from it.

I think the lack of read-only interface is quite unfortunate, but there is probably no way this could be fixed, because it would mean changing the existing .NET collection libraries.

IsReadOnly允许接口为只读,即使它提供了可写的方法。

It's a .Net thing. You cannot implement only some of the interface, and yet they wanted to implement the IDictionary`2 interface - because you can use its querying and conversion methods (so you can pass it to functions that read from an IDictionary`2 ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM