IterableFactoryDefaults trait has the following definition:
trait IterableFactoryDefaults[+A, +CC[x] <: IterableOps[x, CC, CC[x]]] extends IterableOps[A, CC, CC[A @uncheckedVariance]] {
protected def fromSpecific(coll: IterableOnce[A @uncheckedVariance]): CC[A @uncheckedVariance] = iterableFactory.from(coll)
protected def newSpecificBuilder: Builder[A @uncheckedVariance, CC[A @uncheckedVariance]] = iterableFactory.newBuilder[A]
// overridden for efficiency, since we know CC[A] =:= C
override def empty: CC[A @uncheckedVariance] = iterableFactory.empty
}
As the doc says, this trait is used for providing default implementation of fromSpecific and newSpecificBuilder.
Regarding to this, I have the following questions:
Why does IterableFactoryDefaults extend IterableOps trait? To provide default implementation of those abstract methods, we can simply implement the following:
trait IterableFactoryDefaults[+A, +CC[x] <: IterableOps[x, CC, CC[x]]] {
def iterableFactory: IterableFactory[CC]
protected def fromSpecific(coll: IterableOnce[A @uncheckedVariance]): CC[A @uncheckedVariance] = iterableFactory.from(coll)
protected def newSpecificBuilder: Builder[A @uncheckedVariance, CC[A @uncheckedVariance]] = iterableFactory.newBuilder[A]
// overridden for efficiency, since we know CC[A] =:= C
override def empty: CC[A @uncheckedVariance] = iterableFactory.empty
}
Then plug the trait where it’s needed. Isn’t this design cleaner?
It seems that the purpose of IterableFactoryDefaults extending IterableOps is that it can be used alone to provide iterable operation methods. In other words, when implementing a collection satisfying CC[A] == C, there’s no need to extends IterableOps[A, Coll, Coll[A]], we simply extends IterableFactoryDefaults[A, Coll] and all iterable operations are available to the new type.
But if this is the idea, why we can see Iterable actually extends both IterableOps and IterableFactoryDefaults? As in,
trait Iterable[+A] extends IterableOnce[A] with IterableOps[A, Iterable, Iterable[A]] with IterableFactoryDefaults[A, Iterable]
Why do we need Iterable to inherit twice the same set of methods?