patterns icon indicating copy to clipboard operation
patterns copied to clipboard

Anti-Pattern: Intermediate `collect()`ion

Open llogiq opened this issue 10 years ago • 7 comments

I sometimes see this in code from iterative-minded folks, they iterate over something, collecting the result in a Vec. Then they iterate over the Vec, producing yet another Vec.

In most cases, the intermediate storage can be avoided. However, there are two exceptions:

  • When start()ing a number of threads one intends to join() later, the intermediate storage is needed to allow the threads to run concurrently.
  • Sometimes the intermediate storage can help the LLVM optimizer autovectorize some calculations that it would bail on were the iterations fused. In such cases, specific measurements should guide the implementation.

llogiq avatar Oct 23 '15 09:10 llogiq

  • when you are collecting an Iterator<Item = Result<T, U>> into a Result<Vec<T>, U>, but the error production has a side-effect that you need. This actually occurs in rustc, where you don't want to stop reporting errors after the first error.

oli-obk avatar Oct 27 '15 09:10 oli-obk

Collecting early and then iterating over the vector allows one to avoid parameterizing the code that does the iterating over the iterator type, right? I would say that the most common anti-pattern I see in Rust is unnecessarily parameterized functions; e.g. fn foo<W: Write>(w: &mut W) instead of fn foo(w: &mut Write).

briansmith avatar Oct 10 '16 09:10 briansmith

The latter uses a fat pointer+vtable whereas the former does static dispatch, am I right? In that case, it depends on whether you agree to the runtime cost of dynamic dispatch (which is often negligible) or not (e.g. in a tight loop).

llogiq avatar Oct 10 '16 09:10 llogiq

The latter uses a fat pointer+vtable whereas the former does static dispatch, am I right? In that case, it depends on whether you agree to the runtime cost of dynamic dispatch (which is often negligible) or not (e.g. in a tight loop).

I usually see people doing it the parameterized way when performance isn't an issue and/or when it isn't clear that dynamic dispatch is worse than the effects of code bloat that results from parameterization.

briansmith avatar Oct 10 '16 09:10 briansmith

There are other downsides for using trait objects rather than generics - in particular you have to care about object safety which is a fiddly topic.

The preferred solution is impl Trait, but that is unstable and incomplete.

nrc avatar Oct 10 '16 21:10 nrc

The preferred solution is impl Trait, but that is unstable and incomplete.

For this, I can not wait :)

softprops avatar Oct 11 '16 12:10 softprops

My point is that Intermediate collect()ion is often good if one's goal is to avoid reduce type-parameterized code. I'm not debating whether or not that is a good goal.

briansmith avatar Oct 12 '16 19:10 briansmith