Credence.Pattern.NoEnumCountForLength (credence v0.7.0)

Copy Markdown

Detects Enum.count/1 (without a predicate) on a provably-list argument and rewrites it to length/1.

Why this matters

Enum.count/1 goes through the Enumerable protocol, adding dispatch overhead. When the argument is a list, length/1 is a BIF that does the same traversal without protocol dispatch:

# Flagged — argument is provably a list
total = String.graphemes(text) |> Enum.count()

# Idiomatic — BIF, no protocol overhead
total = length(String.graphemes(text))

Why "provably a list"

length/1 only accepts lists — length(1..5) raises ArgumentError, while Enum.count(1..5) returns 5. So the rewrite is behaviour-preserving only when the argument is known to be a list. The rule therefore fires only when the argument is:

  • a list literal ([a, b, c]),
  • a ++ concatenation, or
  • a call (or pipe ending in a call) to a list-returning function — String.graphemes/split/..., Map.keys/values, Enum.map/filter/sort/..., List.*, etc.

A bare variable (Enum.count(chars)) is not flagged: its type is unknown, and it might be a range, map, or stream rather than a list.

Flagged patterns

Only the single-argument form Enum.count(x) (direct or piped). The two-argument Enum.count(x, predicate) is not flagged (it filters and counts in one pass).