"Easy mode" for docs?


#1

Flexibility brings not only implementation complexification, but also doc complexification. Maybe there is a way to battle this?


Consider a impl Trait world and there was a public function

fn qqq() -> impl Mmm;

But after iterations of making it more and more advanced (while retaining backwards compatibility), it ended up like:

fn qqq<X = ResonableDefault>() -> HorribleMonster<Dread,Fear<Danger>>;
impl<T,Y> Abomination<Y> for HorribleMonster<T,Y>;
impl<T,Y> Mmm for HorribleMonster<T,Y>;
impl<T,Y> Atrocity<T> for  HorribleMonster<T,Y>;

Juding just from signature of qqq it’s not immediately obvious that the main thing and main usage of the monster is Mmm, which was clearly communicated by impl Mmm before.

Also type parameter X is only for an obscure optimization majority of users won’t care about.

So for documentation (including compiler messages) purposes qqq still wants to be cute little fn qqq() -> impl Mmm;.


Can there be two modes of rustdoc pages (like a JavaScript toggler): easy mode and reference mode?

In easy mode some defaulted type parameters would be hidden and some return types be replaced with a trait (as if in impl Trait, but in reality it’s a concrete type), maybe some methods hidden outright.

Like an boosted #[doc(hidden)]


It may be implemented as mock module with simplified structs, enums, traits, fns just for the doc, with the compiler checking that the mock module is a subset of the real module.

Or it may be just some doc attributes tuning the way which is easy content and which is advanced content.


Precedent: CMake’s “advanced” options


#2

Some Haskell libraries solve this problem by manually listing specializations in the documentation.

For example, the lens library uses this technique throughout.

Using this method, your example would look like this:

/// Performs the Q three times, returning the M's of all of them.
///
/// This function is highly generic, to allow for Q's that are written backwards
/// or exhibit poor kerning. Most of the time, though, you can think of this
/// function as of this simpler type:
///
/// ```rust,ignore
/// fn qqq() -> impl MMM;
/// ```
fn qqq<X = ResonableDefault>() -> HorribleMonster<Dread,Fear<Danger>> {
    // ...
}

#3

As @lfairy noted, library authors can explicitly list the possible specializations in the documentation (Example). Unfortunately, this is not officially supported: the lack of testing means it can easily go out of date.

I don’t believe there’s an easy way to automatically generate these specializations – and even if you could it might not offer the most useful content. However, it is certainly valuable if one can write these manually. It would require (1) standardizing a syntax for it (2) having rustdoc automatically test their validity.


#4

Another case: deserialize_from in Serde

/// This method is stable and an official public API, but hidden from the
/// documentation because it is almost never what newbies are looking for.
/// Showing it in rustdoc would cause it to be featured more prominently
/// than it deserves.

#5

The way Rustdoc presents traits is noisy and scary-looking in general. For built-in well-known traits like Add and Iterator I wish it transformed the description to just a bit of prose:

Chunks<T> is an Iterator of [T] elements.

rather than dump an unorganized pile of angle brackets:

impl<'a, T> FusedIterator for Chunks<'a, T>[src] impl<'a, T> Iterator for Chunks<'a, T>[src] type Item = &'a [T] fn next(&mut self) -> Option<&'a [T]>[src] fn size_hint(&self) -> (usize, Option)[src] fn count(self) -> usize[src] fn nth(&mut self, n: usize) -> Option<<Chunks<'a, T> as Iterator>::Item>[src] fn last(self) -> Option<<Chunks<'a, T> as Iterator>::Item>


#6

I think a great improvement to simplify the documentation of types would be to remove the methods of a Trait, which the type implements like @kornel mentioned. However there are two downsides;

  1. Any documentation the method has in the implementation is now effectively lost.
  2. If you’re new to a trait the method might not be known to you yet. So if you see code like x.read(buf), know you have to lookup all the traits x implements to find the read method in the Read trait.

#7

How about making them collapsible? [±] It would help to have a global switch to show/hide trait methods.


#8

What about a general switch for “easy/reference” modes, not just some one aspect of it like trait methods?

There must be a way to look at the docs like compiler is looking at source code, so that missing item from docs imply missing (or at least undocumented or unstable) feature. This is the reference mode.

Another, default mode is where unneeded methods, “scary” things or “unrecommended unless there is specific case” features, defaulted type parameters and so on are hidden. Maybe some documentation text paragraphs should also be hidden. This is the easy mode.

Easy mode’s doc text may advice pressing the “show complete docs” switch for some use cases.


#9

Discussed previously here: https://github.com/rust-lang/rust/issues/45720