Skip to content

Conversation

zachs18
Copy link
Contributor

@zachs18 zachs18 commented May 14, 2025

The docs on impl<I: Default> Default for core::iter::Fuse<I> say (as the I: Default bound implies) that Fuse::<I>::default "Creates a Fuse iterator from the default value of I". However, the implementation creates a Fuse with Fuse { iter: Default::default() }, and since the iter field is an Option<I>, this is actually Fuse { iter: None }, not Fuse { iter: Some(I::default()) }, so Fuse::<I>::default() always returns an empty iterator, even if I::default() would not be empty.

This PR changes Fuse's Default implementation to match the documentation. This will be a behavior change for anyone currently using Fuse::<I>::default() where I::default() is not an empty iterator1, as Fuse::<I>::default() will now also not be an empty iterator.

(Alternately, the docs could be updated to reflect what the current implementation actually does, i.e. returns an always-exhausted iterator that never yields any items (even if I::default() would have yielded items). With this option, the I: Default bound could also be removed to reflect that no I is ever created.)

Current behavior example (maybe an example like this should be added to the docs either way?)

This PR changes publicly observable behavior, so I think requires at least a T-libs-api FCP?

r? libs-api

cc #140961

impl<I: Default> Default for Fuse<I> was added in 1.70.0 (#99929), and it's docs and behavior do not appear to have changed since (Fuse's iter field has been an Option since before the impl was added).

Footnotes

  1. IIUC it is a "de facto" guideline for the stdlib that an iterator type's default() should be empty (and for iterators where that would not make sense, they should not implement Default): cc https://github.com/rust-lang/libs-team/issues/77#issuecomment-1194681709 , so for stdlib iterators, I don't think this would change anything. However, if a user has a custom Iterator type I, and they are using Fuse<I>, and they call Fuse::<I>::default(), this may change the behavior of their code.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels May 14, 2025
@zachs18 zachs18 changed the title Change core::iter::Fuse's Default impl to do what it's docs say it does Change core::iter::Fuse's Default impl to do what its docs say it does May 14, 2025
@hanna-kruppe
Copy link
Contributor

Either way (fix the impl or fix the docs) this should probably gain a test since it’s extremely non-obvious from the code alone.

@scottmcm
Copy link
Member

And maybe change the code to either Option::default() just None or to I::default() to help emphasize, too.

@tgross35
Copy link
Contributor

I doubt this will have much of a noticeable impact but we may as well try to measure it.

@bors try

bors added a commit to rust-lang-ci/rust that referenced this pull request May 15, 2025
Change `core::iter::Fuse`'s `Default` impl to do what its docs say it does

The [docs on `impl<I: Default> Default for core::iter::Fuse<I>`](https://doc.rust-lang.org/nightly/std/iter/struct.Fuse.html#impl-Default-for-Fuse%3CI%3E) say (as the `I: Default` bound implies) that `Fuse::<I>::default` "Creates a `Fuse` iterator from the default value of `I`". However, the implementation creates a `Fuse` with `Fuse { iter: Default::default() }`, and since the `iter` field is an `Option<I>`, this is actually `Fuse { iter: None }`, not `Fuse { iter: Some(I::default()) }`, so `Fuse::<I>::default()` always returns an empty iterator, even if `I::default()` would not be empty.

This PR changes `Fuse`'s `Default` implementation to match the documentation. This will be a behavior change for anyone currently using `Fuse::<I>::default()` where `I::default()` is not an empty iterator[^1], as `Fuse::<I>::default()` will now also not be an empty iterator.

(Alternately, the docs could be updated to reflect what the current implementation actually does, i.e. returns an always-exhausted iterator that never yields any items (even if `I::default()` would have yielded items). With this option, the `I: Default` bound could also be removed to reflect that no `I` is ever created.)

[Current behavior example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=a1e0adc4badca3dc11bfb70a99213249) (maybe an example like this should be added to the docs either way?)

This PR changes publicly observable behavior, so I think requires at least a T-libs-api FCP?

r? libs-api

cc rust-lang#140961

`impl<I: Default> Default for Fuse<I>` was added in 1.70.0 (rust-lang#99929), and it's docs and behavior do not appear to have changed since (`Fuse`'s `iter` field has been an `Option` since before the impl was added).

[^1]: IIUC it is a "de facto" guideline for the stdlib that an iterator type's `default()` should be empty (and for iterators where that would not make sense, they should not implement `Default`): cc rust-lang/libs-team#77 (comment) , so for stdlib iterators, I don't think this would change anything. However, if a user has a custom `Iterator` type `I`, *and* they are using `Fuse<I>`, *and* they call `Fuse::<I>::default()`, this may change the behavior of their code.
@bors
Copy link
Collaborator

bors commented May 15, 2025

⌛ Trying commit fe06fc3 with merge 17092ad...

@bors
Copy link
Collaborator

bors commented May 15, 2025

☀️ Try build successful - checks-actions
Build commit: 17092ad (17092ad00ed8fe1e7f81a7e38238ff70779034b1)

@tgross35

This comment was marked as outdated.

@craterbot

This comment was marked as outdated.

@tgross35
Copy link
Contributor

@craterbot run mode=build-and-test

@craterbot
Copy link
Collaborator

👌 Experiment pr-140985 created and queued.
🤖 Automatically detected try build 17092ad
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 15, 2025
@craterbot
Copy link
Collaborator

🚧 Experiment pr-140985 is now running

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot
Copy link
Collaborator

🎉 Experiment pr-140985 is completed!
📊 208 regressed and 149 fixed (631768 total)
📰 Open the full report.

⚠️ If you notice any spurious failure please add them to the denylist!
ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-crater Status: Waiting on a crater run to be completed. labels May 17, 2025
@zachs18
Copy link
Contributor Author

zachs18 commented May 28, 2025

I've looked at the crates.io regressions:

Definitely spurious

Some form of "no space left on device":

  • aeiou-macros
  • april
  • argsyn
  • art_dice
  • async-peek
  • badmf
  • mu_pi
  • puzz-http
  • rstats
  • rusty_audio
  • safe-regex
  • simple-cache-rs
  • standard_card
  • timely-master
  • wallpaper_rs

Some form of "failed to create temporary directory":

  • ambiq-apollo3p-pac
  • async-pidfd-next
  • banka
  • simpl_cache
  • storage-path-generator

"Error building SSL dependencies": artcode

Other OS error ("Resource temporarily unavailable" when opening a file?): cannyls

I think are spurious:

  • due to measuring runtimes or similar: async-retry, dust_dds, ratelimit, shared-resource-pool-builder, simple-clock, slow_function_warning, stringsort, tokio-context
  • due to using env vars from multiple tests (and thus multiple threads): fuel-streams-nats, should-color
  • due to relying on hashmap iteration order: axsys-noun, serde-command-opts
  • due to relying on non-hashmap randomness: rs-tool

Otherwise unreliable/incorrect tests: rayoff, samus, sigalign-core (see linked PRs/issue)

I haven't figured out yet: gouth, rs-store, rust-netrc, sigio, sitrep, there. None seem to use Fuse directly at least (rg -iw fuse (case-insensitive, word-based search) on their sources yields no results).

@tgross35
Copy link
Contributor

Thanks for the analysis. I think we can hand this off to libs-api.

@rustbot label +I-libs-api-nominated +T-libs-api -T-libs

@rustbot rustbot added I-libs-api-nominated Nominated for discussion during a libs-api team meeting. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. and removed T-libs Relevant to the library team, which will review and decide on the PR/issue. labels May 28, 2025
@joshtriplett
Copy link
Member

This makes sense, and it sounds like it doesn't have any issues in crater, so:

@rfcbot merge

@rfcbot
Copy link

rfcbot commented Jun 3, 2025

Team member @joshtriplett has proposed to merge this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this PR / Issue. to-announce Announce this issue on triage meeting and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels Jun 13, 2025
@rfcbot
Copy link

rfcbot commented Jun 13, 2025

The final comment period, with a disposition to merge, as per the review above, is now complete.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

This will be merged soon.

@tgross35
Copy link
Contributor

@rustbot author, to address @camsteffen's comments

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 16, 2025
@rustbot
Copy link
Collaborator

rustbot commented Jun 16, 2025

Reminder, once the PR becomes ready for a review, use @rustbot ready.

…oes.

Add a doctest with a non-empty-by-default iterator.
@zachs18 zachs18 force-pushed the fuse-default-some branch from 9e8af12 to f3d4278 Compare June 18, 2025 21:28
@zachs18
Copy link
Contributor Author

zachs18 commented Jun 18, 2025

@rustbot ready

Assuming #140985 (comment) is good

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 18, 2025
@tgross35
Copy link
Contributor

@bors r+ rollup

@bors
Copy link
Collaborator

bors commented Jun 23, 2025

📌 Commit f3d4278 has been approved by tgross35

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 23, 2025
bors added a commit that referenced this pull request Jun 24, 2025
Rollup of 9 pull requests

Successful merges:

 - #140985 (Change `core::iter::Fuse`'s `Default` impl to do what its docs say it does)
 - #141324 (std: sys: random: uefi: Provide rdrand based fallback)
 - #142134 (Reject unsupported `extern "{abi}"`s consistently in all positions)
 - #142784 (Add codegen timing section)
 - #142827 (Move error code explanation removal check into tidy)
 - #142873 (Don't suggest changing a  method inside a expansion)
 - #142908 (Fix install-template.sh for Solaris tr)
 - #142922 (Fix comment on NoMangle)
 - #142923 (fix `-Zmin-function-alignment` on functions without attributes)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit f50da06 into rust-lang:master Jun 24, 2025
10 checks passed
@rustbot rustbot added this to the 1.90.0 milestone Jun 24, 2025
rust-timer added a commit that referenced this pull request Jun 24, 2025
Rollup merge of #140985 - zachs18:fuse-default-some, r=tgross35

Change `core::iter::Fuse`'s `Default` impl to do what its docs say it does

The [docs on `impl<I: Default> Default for core::iter::Fuse<I>`](https://doc.rust-lang.org/nightly/std/iter/struct.Fuse.html#impl-Default-for-Fuse%3CI%3E) say (as the `I: Default` bound implies) that `Fuse::<I>::default` "Creates a `Fuse` iterator from the default value of `I`". However, the implementation creates a `Fuse` with `Fuse { iter: Default::default() }`, and since the `iter` field is an `Option<I>`, this is actually `Fuse { iter: None }`, not `Fuse { iter: Some(I::default()) }`, so `Fuse::<I>::default()` always returns an empty iterator, even if `I::default()` would not be empty.

This PR changes `Fuse`'s `Default` implementation to match the documentation. This will be a behavior change for anyone currently using `Fuse::<I>::default()` where `I::default()` is not an empty iterator[^1], as `Fuse::<I>::default()` will now also not be an empty iterator.

(Alternately, the docs could be updated to reflect what the current implementation actually does, i.e. returns an always-exhausted iterator that never yields any items (even if `I::default()` would have yielded items). With this option, the `I: Default` bound could also be removed to reflect that no `I` is ever created.)

[Current behavior example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=a1e0adc4badca3dc11bfb70a99213249) (maybe an example like this should be added to the docs either way?)

This PR changes publicly observable behavior, so I think requires at least a T-libs-api FCP?

r? libs-api

cc #140961

`impl<I: Default> Default for Fuse<I>` was added in 1.70.0 (#99929), and it's docs and behavior do not appear to have changed since (`Fuse`'s `iter` field has been an `Option` since before the impl was added).

[^1]: IIUC it is a "de facto" guideline for the stdlib that an iterator type's `default()` should be empty (and for iterators where that would not make sense, they should not implement `Default`): cc rust-lang/libs-team#77 (comment) , so for stdlib iterators, I don't think this would change anything. However, if a user has a custom `Iterator` type `I`, *and* they are using `Fuse<I>`, *and* they call `Fuse::<I>::default()`, this may change the behavior of their code.
@apiraino apiraino removed the to-announce Announce this issue on triage meeting label Jun 26, 2025
tautschnig pushed a commit to model-checking/verify-rust-std that referenced this pull request Jul 3, 2025
Change `core::iter::Fuse`'s `Default` impl to do what its docs say it does

The [docs on `impl<I: Default> Default for core::iter::Fuse<I>`](https://doc.rust-lang.org/nightly/std/iter/struct.Fuse.html#impl-Default-for-Fuse%3CI%3E) say (as the `I: Default` bound implies) that `Fuse::<I>::default` "Creates a `Fuse` iterator from the default value of `I`". However, the implementation creates a `Fuse` with `Fuse { iter: Default::default() }`, and since the `iter` field is an `Option<I>`, this is actually `Fuse { iter: None }`, not `Fuse { iter: Some(I::default()) }`, so `Fuse::<I>::default()` always returns an empty iterator, even if `I::default()` would not be empty.

This PR changes `Fuse`'s `Default` implementation to match the documentation. This will be a behavior change for anyone currently using `Fuse::<I>::default()` where `I::default()` is not an empty iterator[^1], as `Fuse::<I>::default()` will now also not be an empty iterator.

(Alternately, the docs could be updated to reflect what the current implementation actually does, i.e. returns an always-exhausted iterator that never yields any items (even if `I::default()` would have yielded items). With this option, the `I: Default` bound could also be removed to reflect that no `I` is ever created.)

[Current behavior example](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=a1e0adc4badca3dc11bfb70a99213249) (maybe an example like this should be added to the docs either way?)

This PR changes publicly observable behavior, so I think requires at least a T-libs-api FCP?

r? libs-api

cc rust-lang#140961

`impl<I: Default> Default for Fuse<I>` was added in 1.70.0 (rust-lang#99929), and it's docs and behavior do not appear to have changed since (`Fuse`'s `iter` field has been an `Option` since before the impl was added).

[^1]: IIUC it is a "de facto" guideline for the stdlib that an iterator type's `default()` should be empty (and for iterators where that would not make sense, they should not implement `Default`): cc rust-lang/libs-team#77 (comment) , so for stdlib iterators, I don't think this would change anything. However, if a user has a custom `Iterator` type `I`, *and* they are using `Fuse<I>`, *and* they call `Fuse::<I>::default()`, this may change the behavior of their code.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.