One important lesson here is that implementations typically "lock down"
performance decisions. For example, the implementor uses an array lookup
instead of a <value, pair> list because an array is good for the expected
case dense values. However, clients that have sparse values will pay for
the array implementation with big memory allocations and poor reference
locality. These decisions thus mean that various acceptable *interfaces*
have inadequate performance and that eventually limits the code's
reusability.