Rustdoc: distinguish 'Provided' trait methods with 'Auxilliary' sub-category

Take a look at the docs for Iterator:

  • Required Associated Types
    • type Item
  • Required Methods
    • fn next(&mut self) -> Option<Self::Item>
  • Provided Methods
    • [a very long list here]

This is sufficient to convey the minimum that must be implemented and the resulting usable API, but it does not convey which additional "provided methods" it may be useful to implement (libstd impls frequently include size_hint, sometimes also count, last, advance_by).

Suggestion: add a third category of methods to break the docs into three sections; something like:

  • Required Methods
  • Provided Methods
  • Auxilliary Methods

All methods with a default impl would continue to normally go into the "provided" category, but an attribute like #[doc(auxilliary)] would push them to the third category (hence trait Iterator would get some annotations, but most other trait definitions would remain unchanged).


Of course this might be overkill when Iterator is the only target I have in mind, and better trait docs would be (mostly) sufficient.


A partial alternative might be to push methods with a Self: Sized bound (thus excluded from the dyn trait) to a different sub-section which may improve the docs of significantly more traits...

... this does highlight that Iterator::count and Iterator::last have a Self: Sized bound: presumably because there would be very little reason to put these in the vtable for dyn Iterator<Item = T>.

1 Like

Currently the trait-level docs for Iterator state:

This is the main iterator trait. For more about the concept of iterators generally, please see the module-level documentation. In particular, you may want to know how to implement Iterator.

However, optimization and other "advanced" techniques are not discussed in the "how to implement Iterator" doc. Maybe they should. OTOH, I believe that the best practices wrt iterator implementation have been somewhat in a state of flux; for example, I believe it's now understood that the upper bound of size_hint is essentially useless because it cannot be trusted. Also, nowadays many provided methods and adapters are implemented in terms of try_fold, and it can even be considered the most fundamental iterator method and the most important to make fast. Even next can and possibly should be implemented in terms of try_fold.

One version of this I'd like to see is #[final]: provided methods that cannot be overridden.

That would be helpful in allowing unsafe code to trust those methods (without needing to be an unsafe trait) but also just to communicate to people "look, there's really no time you'd ever want to override this".

(Like there's no fruitful way to override Iterator::map, for example. Though we probably wouldn't be able to mark it #[final] for semver reasons.)

EDIT: Oops, I meant #[final], as CAD mentions below, not #[sealed].

2 Likes

We have final as a reserved keyword, and I've played with the idea of calling such provided methods final fn. Effectively baking in a trait extension trait as part of the main trait docs/body. A fun extra power this gives the compiler is that it can choose to omit a final trait method from the vtable when its body can be compiled polymorphically. (Probably only would want to when the body would contain at most one otherwise monomorphic call to self.)

But unfortunately yeah, you can currently implement the Iterator methods with unimplemented! or some other diverging method body. This would make preventing doing so breaking and against std's strict compatibility standards.

1 Like

Another one is that final fns would be allowed in #[marker] traits which are otherwise not allowed to have associated items.

2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.