Suggestion: rustdoc should use fully-qualified names for anything not declared in the documented crate.
Here is an example from Tokio that I just came across:
pub trait ServerProto<T: 'static>: 'static {
type Request: 'static;
type Response: 'static;
type Transport: 'static + Stream<Item=Self::Request, Error=Error> + Sink<SinkItem=Self::Response, SinkError=Error>;
type BindTransport: IntoFuture<Item=Self::Transport, Error=Error>;
fn bind_transport(&self, io: T) -> Self::BindTransport;
}
Notice the <Error=Error> parts? I propose that they should be fully-qualified as <Error=std::io::Error>, which is a lot clearer, IMHO.
(Some previous discussion of the idea here: https://github.com/rust-lang/rfcs/pull/356#issuecomment-65940929)
It sounds like always using full paths for anything from a different crate would be a good idea, but it may also sometimes be warranted intra-crate, e.g. to more clearly distinguish std::result::Result and std::io::Result. I'm not sure what the precise rule should be in that case. Maybe just "use the full path if the current crate has more than one item with that name" (and maybe it should be a relative path if it's from a submodule of the current one; and probably elide it if it's self::).
Couldn't we also (even as we try to choose a sensible default) expose the choice in the rendered rustdocs themselves, e.g. as a "show full paths" checkbox (or a 3-way always/never/sometimes)? There's no rule that the generated pages have to be static.
@glaebhoerl I think we should try to avoid ambiguities but otherwise keep the paths short.
It shows the full path on mouse over already. An option would be showing ..:: when ambiguities arise. Yet, another option would be to consider either the use statements in the doc tests, perhaps provided they were consistent, so one doc test with use std::io; could give io::Error here.
@eddyb Do you feel like the proposals above would cause excessively long paths too often?
@burdges Yes, I noticed that, but it would be rather nice to be able to see at a glance what's going on... Also, I can currently use rustdocs with only my keyboard (no mouse), and I would like to keep that up!
@glaebhoerl
Couldn't we also (even as we try to choose a sensible default) expose the choice in the rendered rustdocs themselves, e.g. as a "show full paths" checkbox (or a 3-way always/never/sometimes)? There's no rule that the generated pages have to be static.
That's true, but I think there was some discussion before about how javascript is required for rustdocs... I personally don't mind one way or the other since I use chrome or firefox, but maybe something to keep in mind?
@mark-i-m Yes, you can get a feel for this when looking at types in error messages, it's quite bad. I'd like only to prefix what's overlapping with the prelude, i.e. io::Result<Vec<u8>> is perfect.
@eddyb Hmm... that seems a bit unsatisfying to me, though. I don't know libraries well enough to know off-hand that io in io::Result<Vec<u8>> is std::io and not tokio_core::io (which it turns out doesn't have a result type) or something else...
I went and did a case study with a recent error message I got:
std::result::Result<tokio_io::codec::Framed<T, proto::PaintCodec>, errors::Error>
Result<Framed<T, PaintCodec>, Error>
You are right that the second is a lot easier to read if I know where all the types come from, but unfortunately, I don't (and I wrote this code 2 days ago). Something did occur to me as I was looking at this though... Currently rustdocs has this nifty expand/collapse feature. It's great if you just want to do a quick lookup for the name of method or argument order or something. Then if you want a closer look, you can just expand that item. Taking inspiration from @glaebhoerl's suggestion above, we might consider showing the full name of a type for expanded items and only the condensed type for collapsed ones.
I've previously wanted a tool to recommend optimizations to use lines, so like rustfix --use "Your code might be more readable if we use std::io::{A,B,C}; and .. with use std::*; and io::A, etc. May I try? (y,n)" If that existed, then it might converge towards a consensus on optimizing use, and docs could be produced to that consensus.
I'm not quite sure I followed that. Could you give an example of how rustdocs would change? Are you saying that rustdocs should include the uses of a module and then keep the short names?
No. I think docs cannot use the actual uses present in the definition code because those should differ from the uses typical for consumers. And docs should represent the typical consumer. If a consensus emerged about what uses were typically optimal, then docs could follow that without regard to what the definition code does. This is also why I suggested basing it on the uses present in doc tests.
I suppose "go up levels until all ambiguities get resolved" sounds fine, maybe along with "stop early if only this item appears under its own name in a use line in a doc test". If various doc tests contained use foo:io;, use bar::io as bar_io;, use baz::io::Error, but not use std::io etc, then baz::io::Error becomes Error and foo::io::Error becomes io::Error, while bar_io::Error becomes bar::io::Error and std::io::Error remains the full path too. It would not stop early when doc tests conflict, but you could suppress literal conflicts with lines like use std::io as io in doc tests. A bias in favor of the current crate and/or std and core might make sense too, but not exactly sure how that might work.
I think docs cannot use the actual uses present in the definition code because those should differ from the uses typical for consumers.
Well, yeah, but it could figure out what names a user would have to use, right? I don't know how much work that is, though... Also, I feel like it would still be a less useful solution than just using fully qualified names because you would have to do a lot of scrolling.
I suppose "go up levels until all ambiguities get resolved" sounds fine ...
After thinking some more about this, I am not sure this would work after all. The reason is that a name might be unambiguous without it being obvious. For example, suppose I actually am using std::result::Result. If I read the docs and it just says Result, I will still wonder which crate it comes from. In other words, the real requirement is that names are (1) unambiguous and (2) clearly so.
@eddyb Did any of these suggestions/arguments seem convincing to you? I'm inclined to open an actual RFC, but I don't want to suggest a feature that will make half of rust programmers annoyed at the other half :stuck_out_tongue:
Going to close this since there is an actual RFC to reduce clutter
Most helpful comment
(Some previous discussion of the idea here: https://github.com/rust-lang/rfcs/pull/356#issuecomment-65940929)
It sounds like always using full paths for anything from a different crate would be a good idea, but it may also sometimes be warranted intra-crate, e.g. to more clearly distinguish
std::result::Resultandstd::io::Result. I'm not sure what the precise rule should be in that case. Maybe just "use the full path if the current crate has more than one item with that name" (and maybe it should be a relative path if it's from a submodule of the current one; and probably elide it if it'sself::).Couldn't we also (even as we try to choose a sensible default) expose the choice in the rendered rustdocs themselves, e.g. as a "show full paths" checkbox (or a 3-way always/never/sometimes)? There's no rule that the generated pages have to be static.