There are generally two kinds of collection frameworks: those without duplicate code but losing the collection type, and those which preserve the collection type but have duplicated code.
Most fall into the first camp, e.g. in .NET, everything returns
IEnumerable, in Ruby, everything returns
Array, in Python, everything returns an iterable, etc. Smalltalk falls into the second camp: all operations preserve the type, but at the cost of simply duplicating the operations for every type.
Scala has the first large-scale collections library I know of that manages to be type-preserving without duplication. The key idea is the concept of builders, which are objects that know how to (efficiently) build collections of a specific type. So, an operation like
filter only needs to look up the builder for the collection type and then it can use this builder to efficiently build the result collection without actually having to know about each and every collection there could ever be. In Scala, it is the type system (or more precisely implicit resolution) that takes care of this lookup at compile time (so that there is no runtime overhead), but it can just as well be done at runtime.
Note, however, that type-preserving collection operations may have surprising consequences. For example, you don't expect
map to change the length of a collection, but
map(Set(1, 2, 3, 4), lambda el: is_even(el)) == Set(true, false)
Also, in some cases, you actually have to return a more general type, or another related type. E.g., a
ByteSet can only contain the numbers 1-255, so
map(ByteSet(16), lambda el: el.__str__()) == Set("16")
map(ByteSet(16), lambda el: el ** 2) == IntSet(256)
So, if you want to build a type-preserving collections framework, you can look at Scala's collections framework and its builders and the
CanBuildFrom implicit type-level machinery. I would suggest you look at the strawman proposal for the simplified and redesigned framework in Scala 2.13 instead of the current release since the latter one is considered to be overengineered and overly complex.