Credence.Pattern.NoFilterThenFirst
(credence v0.7.0)
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