Context
I'm building an application that benefits from versatile collection wrappers, so I've set my sights on the Hack collection interfaces. Two of them are particularly promising: KeyedContainer<+Tk, +Tv>
and ConstIndexAccess<Tk, +Tv>
. The square-bracket access syntax allows Tk
to be covariant in the former which has proven very useful — getter methods otherwise would require Tk
in the argument (contravariant) position. That means I can access elements in sublinear time (argument-position Tk
), or loop over the collection and access keys (return-position Tk
) as I wish. The downside is that KeyedContainer
is impossible to extend usefully: it doesn't define any methods.
At the moment, I need a mutable keyed collection type with an immutable ancestor. With this restriction on KeyedContainer
, I'm considering biting the bullet by giving up keyed foreach
and using ConstIndexAccess
, which defines an explicit getter and has a mutable IndexAccess
child from which MutableMap
and MutableVector
inherit.
Issue
The invariance of Tk
makes ConstIndexAccess
less powerful of a type, but also suggests that maybe there is some way to read keys from them. Is this the reason that ConstIndexAccess
isn't contravariant on Tk
? None of its descendants are covariant on Tk
, and it is not possible to iterate using foreach
. All other standard Hack contracts as far as I can tell have as flexible variances as possible except this one.