But that already happened with the collections rewrite for 2.13. Even though Traversable is a more general concept (where control of progression is with the collection), it turned out that there were no collections for which an Iterator (where control of progression is inverted and placed with the caller) was impractical. So it was dropped.
And View was reformulated so that it acts almost identically to () => Iterator. When you need to do something once, you use an Iterator. If you need to use it multiple times, but you don’t want to build a copy and use that, you use a View. It can be more optimized than () => xs.iterator.<iterator operations>, but isn’t guaranteed to be. Is it worth the overhead, or should we tear it out? I’m not sure it’s used enough to have been worth building, but since it’s there, may as well leave it.
That’s CollectionType.newBuilder[EltType]. You terminate it with .result().
If it’s awkward to string along the builder, you can also create an iterator and use to(CollectionType). If you want to defer the decision, use the generic Buffer[EltType] and to(TargetCollectionType).
I really don’t see how it could be dramatically easier. Maybe we need to emphasize it more. But it’s already pretty awesome.
Did you know you can parallelize operations without bringing in the parallel collections dependency, if you’re on the JVM? Use scala.jdk.StreamConverters and your collections can become Java Streams with .asJavaParStream and then toScala(TargetCollection) to get back–or you can fragment the work yourself by using collection.stepper and the methods on that.
The collections are already really awesome. They are big, true; the biggest problem is getting lost in them. The second biggest problem is that they’re nominally extensible, but there are a lot of tricks to extending them, so it’s easier to just give up. The third biggest problem is that if you want something that works generically over all collections, you need some pretty advanced concepts, but it actually is only a few lines of code. The fourth biggest problem is that there aren’t many high-level methods for mutable collections. They’re just not straightforward (which maybe isn’t unreasonable, given that this is employing some very heavy lifting to make everything work like magic). All these problems are intentional tradeoffs, though. If it had been done differently, something else would suffer, sometimes a lot. Small collections = re-invent the wheel a lot. Inextensible = your stuff can never “just work”. Easy application = dedicated compiler magic that you can never have for your library and/or collections that lose types left and right (like Java). Less mutable support = concession to immutable-as-typical and already-too-big.
So we can discuss, but I think the existing hierarchy has an awful lot going for it.