Credence.Pattern.NoFilterThenFirst (credence v0.7.1)

Copy Markdown

Performance rule (fixable): Detects Stream.filter/2 piped into Enum.at/2 with a literal 0 index.

Stream.filter is lazy, so Stream.filter(coll, pred) |> Enum.at(0) evaluates pred only until the first match — exactly what Enum.find/2 does. The rewrite is behaviour-preserving, including the number of predicate evaluations (so side-effecting or raising predicates behave identically).

The eager Enum.filter/2 form is deliberately not flagged: it evaluates pred on every element, whereas Enum.find/2 stops at the first match. With a side-effecting or raising predicate the two diverge (e.g. a predicate that raises on a later element crashes the Enum.filter form but not the Enum.find rewrite), so the rewrite would not give the same answer.

Flagged

Stream.filter(numbers, &(&1 > 10)) |> Enum.at(0)
Enum.at(Stream.filter(numbers, &(&1 > 10)), 0)

Not flagged

Enum.filter(numbers, &(&1 > 10)) |> Enum.at(0)   # eager: changes pred evaluation
Stream.filter(numbers, &(&1 > 10)) |> Enum.at(1) # not index 0
Stream.filter(numbers, &(&1 > 10)) |> Enum.at(0, -1) # has default arg
Enum.find(numbers, &(&1 > 10))                    # already idiomatic