Confusion about the definition of IterableFactoryDefaults

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?

I think a few different variations of this theme would have worked equally well. Some of this is down to preference or simply coincidence.

IterableFactoryDefaults should extend IterableOps because it needs access to iterableFactory. Having a separate definition for it doesn’t look very clean to me. But we could have used a self type instead of extending the trait.

Extending both in traits like Iterable is not necessary but I find it cleaner. The intention is not that you extend IterableFactoryDefaults. The intention is to extend IterableOps and also mix in IterableFactoryDefaults.

I see. Thank you.

IMO, self type might be better, because then we wouldn’t have had one set of methods overriding another set of identical methods in Iterable.

How do I mark question as solved?

No such concept, as far as I know – this is a discussion forum, not a Q&A site like StackOverflow…