This is a design/philosophical question.
I have and use a Buffer
implementation which has a maximum size, and will drop elements from the front as new elements are added at the back - a useful mini tool for working with windows over other collections. Similarly, I have an immutable CappedSet
which serves as a LRU cache with an upper bound on the number of elements: when new elements are added to a full set, the returned set will not contain the same number of least recently used elements.
However, I now have doubts if I should have implemented Buffer
and immutable.Set
at all, as the contract is altered, which may potentially lead to confusion. What’s your take on both cases? Does it differ between mutable and immutable collections? In a sense, the immutable way of creating new collections from old ones is distinct from the nature of the collection itself, or how elements may be accessed. Dropping standard interfaces will considerably reduce the usability: Set.intersect
et.al. will not work with a CappedSet
, all existing copyToBuffer
methods wouldn’t be possible to use.
A conceivable compromise would be to extend only Iterable
, but mix in SetOps[E, CappedSet, CappedSet[E]]
/SeqOps[E, WindowBuffer, WindowBuffer[E]]
. Lack of these interfaces would hurt the most, as they expose exactly the API I need, just with some semantic changes, and the implementations of the majority of methods there works just as well under new circumstances. What’s the least surprising solution in your minds?