Iterable is Matchable but IterableOnce is not. Is there a fundamental reason for that?
Matchable is an opt-in marker that says “decomposing values of this type with pattern matching cannot break the abstraction in an unexpected way.” If a trait does not extend Matchable the compiler merely emits a warning when you try to match on it, but library authors can decide case-by-case whether that extra promise is safe for their types.
IterableOncehas onlyAnyas a super-type – it is not declaredMatchable(IterableOnce)- Concrete sub-types may add the promise themselves; for example
IteratorandIterableboth inheritMatchabledirectly in the library definition (Iterator)
Why the library stops at IterableOnce.
-
IterableOnceis deliberately minimal: the only thing it guarantees is that you can obtain one iterator. A match expression such asxs match case Seq(a, b) => … // uses Seq.unapplySeqwill traverse the value to discover its shape. If
xsis really anIterator, that traversal consumes the iterator, changing its subsequent observable behaviour. Requiring the user (or the subtype) to say “yes, this is match-safe” forces them to think about that side effect. -
Some one-shot data sources (database cursors, input streams, generators, etc.) implement
IterableOnceprecisely because they do not want a second traversal. Marking the root trait asMatchablewould silently make those types decomposable, opening the door to subtle bugs. -
The extra promise matters for type-soundness, too.
Matchableis used by the compiler to forbid pattern matches that could pierce opaque or abstract type boundaries (The Matchable Trait). Keeping the root trait outside that promise leaves room for user-defined single-pass collections whose internals must stay hidden.
Why Iterable and Iterator still extend it.
Iterableis multi-pass by contract, so matching is harmless.IteratorextendsMatchablefor backward compatibility: a great deal of existing code relies on matching over iterators, and the library authors judged that the convenience outweighs the risk. (You still need to remember that the iterator will be advanced by the extractor.)
So there is no deep type-theoretic limitation—just a conservative library design: the most generic collection trait stays neutral, and each concrete subtype opts in only if its semantics make pattern matching a safe operation.
really?
do you have a different opinion?
Well, it’s hard to have definite opinions about what might be out there in the wild.
But I personally don’t recall ever seeing Scala code that pattern matched on an iterator. Not in a codebase, and not in our forums and chat rooms, either.
Iterator doesn’t have an extractor, nor does IterableOnce, so I don’t understand the basis for claiming that “the iterator will be advanced by the extractor”. Can you show an example of that…?
I suspect Iterators are Matchable merely because Iterator extends AnyRef, and not for any other reason. (As you point out above, IterableOnce only extends Any.)
we could be both right or wrong, and I agree with you.