Why IterableOnce is not Matchable?

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.

  • IterableOnce has only Any as a super-type – it is not declared Matchable (IterableOnce)
  • Concrete sub-types may add the promise themselves; for example Iterator and Iterable both inherit Matchable directly in the library definition (Iterator)

Why the library stops at IterableOnce.

  1. IterableOnce is deliberately minimal: the only thing it guarantees is that you can obtain one iterator. A match expression such as

    xs match
      case Seq(a, b) => …        // uses Seq.unapplySeq
    

    will traverse the value to discover its shape. If xs is really an Iterator, 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.

  2. Some one-shot data sources (database cursors, input streams, generators, etc.) implement IterableOnce precisely because they do not want a second traversal. Marking the root trait as Matchable would silently make those types decomposable, opening the door to subtle bugs.

  3. The extra promise matters for type-soundness, too. Matchable is 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.

  • Iterable is multi-pass by contract, so matching is harmless.
  • Iterator extends Matchable for 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.

3 Likes