-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Elide clone operation when calling iter::Cloned::advance_{back}_by()
#90209
Conversation
r? @m-ou-se (rust-highfive has picked a reviewer for you, use r? to override) |
Skipping |
Ideally it would be limited pure(ish) closures, but the trait system can't express that so it would have to be some approximation based on |
After the discussion in #92543 I took another look at I could do that here or in a separate PR. |
Seems fine to me, but let's quickly get some more eyes from @rust-lang/libs-api on this. :) |
rust-lang/rust-clippy#8203 attempts to tackle the perf footgun from the other side. I'm not on libs, but I would favor a two-pronged approach where we try to elide clones where possible and have the lint help people deal with the remaining cases. With that said, I see that the current behavior is in place since 2015. However unlikely, somewhere someone could have implemented a side-effectful |
This is a change in user-visible behavior.
Combined with the `iter::Cloned::advance_by` implementation this leads to fewer clone operations
ac9bdb1
to
37206a2
Compare
Betas already get crater runs. Not sure if it's worth doing a separate one for this. |
I'm personally hesitant to merge this, even with a crater run. It seems to violate compositional reasoning: if people know what I absolutely think it's reasonable to optimize these away for This is less a question of "will we break some existing code", and more that it seems like especially surprising behavior. Are there real-world workloads in which people call (Also, whether we make this change or not, I don't think we should add the comments suggesting we'd skip other things that are more likely to have side effects, such as closures.) |
That depends on what the simplified mental model of The problem with "know what X does" is kind of oversimplifying, because what it really does is return an adapter and adapters are more complicated than just
They're common mistakes. I mostly but not exclusively see them in advent-of-code style exercises or test code, but that suggests that a naive model that people have is only about the outcome of the iterator, not about the order in which adapters are applied. And it often is a very convenient model, a "sufficiently smart And it can be more subtle than that. E.g.
Well, that's what I'd try to do next, optimize away |
@joshtriplett I hear you. While there is no guarantee of side effects in iterator operations in general, code might reasonably depend on them as the current situation has effectively been stable since 2015. On the other hand, while we will soon have a clippy lint that can reduce the impact of this problem, it can only reason locally and thus will always miss some cases. And avoiding alloc churn is an attractive optimization. So while I can certainly relate to your hesitation, we may want to at least think of a path to include these optimizations, perhaps as part of the next future edition. While not as good as getting the performance right now, it would at least give us a future to await (pun totally intended) and in the meantime we can test & benchmark with this PR. |
Closing this per discussion in this week's libs meeting. To summarize:
|
Should we then document the current behavior or at least make clear that we don't offer any performance optimization at least for this edition? I might reopen #92543. |
Well, if we might want to make another attempt in the future then it might cause less confusion by not saying too much. On the other hand the guidance to avoid unnecessary clones can be useful. So maybe it would be better to phrase it in a way focusing on the latter part. |
add perf side effect docs to `Iterator::cloned()` Now that rust-lang#90209 has been closed, as the current state of affairs is neither here nor there, this at least adds a paragraph example on what to expect performance-wise and how to deal with it to the .cloned() docs. cc `@the8472`
This is a change in user-visible behavior. It will not only affect
advance_by
(which is still unstable) but also the stablenth
,nth_back
andSkip
,Take
and other adapters that make use of these methods.It is also a bit of a test-balloon, if it gets approved there are a few more places where other side-effects could be skipped too.
I'm not sure if it is needed at this stage, but a note about side-effects could also be added to the
std::iter
module.Part of #77404