-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
rustdoc: some trait methods appear as "hidden undocumented items" #56546
Comments
What's the problem with that? Those items don't have documentation and are therefore using the one from the trait definition. They are undocumented, that's a fact. What do you suggest we should do instead? |
In my specific example with the Clone trait, I believe the old behavior produces good results because the trait method documentation is written in such a way to make sense for all types that derive Clone. So my initial suggesting would be to switch back to the old behavior of taking the documentation from the trait if the impl does not provide one. However, I can imagine that this isn't true for all traits, and there may be examples where applying the trait documentation to the implementation might not make sense. Do you know if there are specific examples of this? Was this related to why this behavior was changed? The root of my complaint is that categorizing important methods like I suppose one way to resolve my complaint would be to manually duplicate the trait documentation onto the impls, but this seems tedious and error-prone 😃 |
Hiding the methods was deliberate. The idea is that when looking at a type that implements a bunch of standard traits but hadn't put special notes on any of them, the only important thing the user needs to know is that the trait is implemented. Seeing your comment, i bet the verbiage could be improved, but the feature itself was deliberately added to try to keep the page length from getting excessive. |
If you expand the "undocumented" items, rustdoc already does that for you. The impls are undocumented, so we copy over the trait's documentation. Again, the idea is that if you see the same trait everywhere, and a given implementation doesn't add any extra documentation, just knowing it's there is enough. The behavior was added in #54162 if you want to read over that thread. |
Thanks for sharing the relevant issue number. I am certainly sympathetic to the issue of page length. I think that collapsing the trait section by default is a good step, but I still maintain that classifying these methods as "hidden undocumented" is confusing and misleading (especially to new users who may not be familiar with these standard traits). Are you open to suggestions on how to improve this? I think one possibility would be to automatically expand the method docs when expanding the trait (since currently expanding the trait shows nothing of value). |
I think this would be better if the default impls also appeared under the "undocumented" items. Currently it looks sort of strange when a bunch of default impls are shown but the most important items are hidden. |
I ran into this issue when reading the docs for the I see how this feature is helpful for traits like |
The same issue is present in the embedded_hal world. Nearly all the functions from the embedded_hal crate are hidden in the stm32f1xx_hal docs. It seems weird to always hide trait impls as there could be some very useful functions in there, as is the case in stm32f1xx_hal |
@TheZoq2: You don't look at the problem as a whole: in this case they could all be expanded, it wouldn't change much. But in some cases where a type has a lot of trait implementations, it becomes very complicated to read. The current orientation would be to reformulate the sentence, not to re-expand everything automatically. |
Perhaps a trait could indicate at the definition point that its documentation should be expanded automatically? Like @nstoddard's suggestion. The issue seems to be that there are two types of traits:
Whether this behavior should be opt-in or opt-out is a good question, though. Edit: another possible solution, let the documentation for a given type 'promote' certain traits it implements, to be shown expanded directly under the inherent impl. |
Not all undocumented items under For example: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html#implementors Here, some of the Is this an unrelated bug? |
In fact sometimes this leads to only showing deprecated items per default while not showing the actual public API:
Two sub-items appear: "Show hidden undocumented items" and Similarly, for the second "impl CommandExt for Command" (for Windows), the only item is also folded as "hidden undocumented". So there is certainly a bug here where some methods are hidden and others are not, for no apparent reason. But beyond that, I think hiding them at all is a bug in the case noted above: Note that I already clicked on the I understand not unfold trait impls per default as there can be many of them, but do they really have to be hidden behind two clicks? |
I think it would be more intuitive to also hide functions with default implementations when they're not overridden. Yes, they're technically documented since there is some documentation on the default implementation, but there is no "overridden" documentation inside the Consider the following example on why the current behavior is confusing: pub trait Foo {
/// Do something
fn do_something(&self);
/// Do something twice
fn do_something_twice(&self) {
self.do_something(); self.do_something();
}
}
pub struct Baz;
impl Foo for Baz {
/// Do something special since this is a Baz instance and bla bla…
fn do_something(&self) {
println!("Foo");
}
} The generated docs look like this: The current implementation shows the default method This leads to confusing docs, especially when no implementations contain "overridden" documentation: pub struct Bar;
impl Foo for Bar {
fn do_something(&self) {
println!("Bar");
}
} Now The user that sees this documentation doesn't know if |
@phil-opp Can you open a specific issue about this one please? (and ping me on it) |
@GuillaumeGomez Sure! I opened #62499 for this. |
Thanks! :) |
Here's another example of a headache with the current behavior:
|
I also find it a bit confusing, I wanted to look up the |
At the very least, it would be nice not to label the hidden methods as "undocumented" (which they aren't) but as "documented in the trait" or somesuch. "Undocumented" suggests "I won't need them anyway". |
@Amityville-DE mentioned the "Important traits" icon to the left of the Specifically, a trait is "important" if it is documented with the (currently unstable) Given that, would it be possible to show the documentation for important traits, and hide it for other traits? That might present a bit of a compromise and prevent some of the confusion mentioned above. EDIT: Actually, it looks like the |
The generated rustdocs seem to have regressed over the past few years. For example the cgmath Point3 docs from January of 2019 have the traits expanded by default and the traits from the crate seem to be sorted to the top: Today, there there appears to be more traits referenced in the docs but nothing is expanded and finding the traits from the crate is difficult: (Scrolling all the way down....) |
In my MIDI device interfacing library I'm using traits with default functions to share the code for common capabilities between device trait FunctionalitySet1 {
/// Elaborate documentation...
fn do_something(&mut self) {
// ...
}
// ... more methods, all documented here within the trait
}
trait FunctionalitySet2 {
/// Elaborate documentation...
fn do_fancy_thing(&mut self) {
// ...
}
// ... more methods, all documented here within the trait
}
trait FunctionalitySet3 {
/// Elaborate documentation...
fn do_something_exotic(&mut self) {
// ...
}
// ... more methods, all documented here within the trait
}
// Depending on which capability sets each hardware device supports, we can just implement the
// corresponding traits.
struct DeviceA { /* ... */ }
impl FunctionalitySet1 for DeviceA {}
impl FunctionalitySet2 for DeviceA {}
struct DeviceB { /* ... */ }
impl FunctionalitySet3 for DeviceB {}
struct DeviceC { /* ... */ }
impl FunctionalitySet1 for DeviceC {}
impl FunctionalitySet3 for DeviceC {} This approach is really great for concisely modeling hardware with shared functionality. It's elegant and completely eliminates duplicate code across devices. But unfortunately, rustdoc yields really bad results on this kind of code. The documentation is super scattered and incredibly hard to find. Look at how much work and page navigation needs to be done just to see the documentation on the methods of What to do instead?The proposal by @agrif seems ideal to me. It would allow you to annotate traits with #[doc(inline)]
trait FunctionalitySet1 {
// ...
}
#[doc(inline)]
trait FunctionalitySet2 {
// ...
}
#[doc(inline)]
trait FunctionalitySet3 {
// ...
}
// ... Below is a shopped image to demonstrate what the rustdoc output should look like, after applying And here, again, the video showing how convoluted it is right now: https://streamable.com/nhrqrr Final wordsThis writeup was quite some work. I would greatly appreciate if my |
This seems like it would be a reasonable first project -- what is the process for getting this done? Just a PR, or is there some other thing needed first? |
Sorry, I just got in the conversation. The reason behind the fact that there isn't all the documentation there is simply because we had very huge browser issues (just imagine the |
There's two issues here though.
Could rustdoc be made smart enough to prioritize trait impl docs from the current crate (i.e. the crate you ran cargo docs on) so that:
|
This is not optimal in my opinion. It would seem very weird that some impls have full documentation while others don't. This is just not coherent. Also, impls are sorted alphabetically and I don't want to change it. You can see the hidden documentation by clicking on the trait, which is an annoying extra step but remains an acceptable compromise. Still better than having your browser crashing when trying to get a page. |
@GuillaumeGomez what about my minimal suggestion to change "undocumented" to "documented in trait"? |
That wording however would be a great improvement so I totally support it. 👍 (sorry, I caught up really quickly with this thread) |
I'll try to summarize a bit: Problem: Showing all trait functions' documentation even the ones that aren't explicitly documented in the implementor's code file, leads to overblown page sizes and browser crashes. Possible solutions:
1 has the advantage that there's no special treatment of any kind; as GuillaumeGomez said: The disadvantage of 1 is that, well, it makes it almost impossible to navigate the docs of a trait-heavy crate (like Any of the solutions 2, 3 and 4 solve the big navigation problems that 1 has. So, weighing advantages against disadvantages; I strongly prefer navigable docs in trait-heavy crates, even if it does come with mild incoherence issues (and we've accepted those in the past already, why not now). |
If you're talking about not hiding functions inside the "show undocumented items" thingy, it can be discussed. But adding more content to the pages will bring browser issues and on that we can't do much unfortunately (we're talking about HTML more than 20MB in size, maybe even more, I need to find the original issue). |
I see. Solution 4 gives you control over the amount of embedded trait documentations on a given page, and with such, over the page size. What do you think about that? |
The whole std impls are using inline, so again, not possible. :-/ |
What do you mean "are using inline"? The feature I'm proposing doesn't exist yet, how can they be using it |
Sorry, I made the confusion with |
I'd argue that this is on the crate author. If the crate author explicitly instructs rustdoc to embed trait documentation by blindly sticking In any case, it would also be possible to gate this functionality behind a flag or something. That makes it even more unlikely that users mistakenly abuse
That's a valid concern. This is also why initially I preferred solution 3 over 4: with solution 3, However, the disadvantage of solution 3 is that the trait implementor has no control over the size of their rustdoc output. If they happen to have implemented many Weighing advantages against disadvantages:
I'd prefer solution 4 ( Also, explicitness is generally good - and solution 4 is definitely more explicit and obvious than the slightly-magic solution 3. |
I think we have to trust documentation writers to be responsible users of the tools given to them. There is always the possibility of abuse. But if that happens, then we must educate the crate author about best practices for documenting their code so that their end users have the best experience. I am also a fan of I suspect that stdlib might not make use of this feature, and so I would like to reiterate the point in my original issue: Describing important methods like |
I feel like we're back in the early debates of Rust when C and C++ developers were arguing that it was up to the developers to not mismanage memory and pointers. :p My stand here is as follow: we should strongly limit any possibilities of letting developers do something wrong. And I think that adding |
Given the case where the trait is not expanded by default would it at least be possible to automatically expand the hidden items when expanding the trait. Usually nothing is explicitly documented so one needs to click two times for anything to appear. I find this quite annoying and it doesn't seem to serve any purpose. If this change is supported I would like create a PR. |
I don' think that's really the case. We're just saying that the old behavior was more useful, although it had other issues. Finding the best of both worlds seems to be the challenge. I'm not terribly fond of having to opt-in to better documentation via an attribute.
I think the current behavior is that they are hidden unless you override the docs. I'm suggesting that foreign implementations (that don't override the docs or methods) could be collapsed by default while local implementations would always be expanded by default. The later half is the only real change that I'm proposing. I think that the first part is how it currently works. |
In general I think a better solution would simply be to have trait impls contracted by default. And showing all items when expanding them. This will lead to even shorter pages than today and would in my opinion be more intuitive and require less clicking. Then if a user wants to see everything they can simply press the expand all button. I think the other issue with the |
Just to be sure: when you say this, you only mean with the current content right? Because if not, the problem is simply that the HTML is too big, whether or not it's displayed. |
Yes, that is correct. I don't mind having to navigate to a new page to see the full documentation and the HTML issue is quite understandable. |
Ok, on this we can definitely try to do things better. |
These days, the latest docs no longer hide the |
Using the
Clone
impl forVec
as an example, here's what the latest stable docs look like:Whereas the latest nightly docs look like this:
This issue was mentioned #56073 but I believe this issue is important enough to pull into its own issue. I also think this issue is a candidate for a "regression-from-stable-to-nightly" flag.
The text was updated successfully, but these errors were encountered: