4 ms·
> it's often better/easier to read the docs in-situ in the code Could you elaborate on this? It's really surprising to me. Some reasons why I'm surprised to he
by burntsushi 4y ago
> it's often better/easier to read the docs in-situ in the code
Could you elaborate on this? It's really surprising to me. Some reasons why I'm surprised to hear you say it:
* The actual public API isn't necessarily always obviously clear from the source code. For example, if you see 'pub struct Foo;', that doesn't mean it's actually in the public API of the library. rustdoc takes care of figuring out what exactly is exported.
* Viewing it in a web browser has the benefit of it being nicely formatted.
* The web browser also has hyperlinks you can follow. Your editor environment probably handles a fair bit of these with 'goto definition', but the prose itself might have hyperlinks that aren't easily followed in the context of your editor.
I think the first reason is the most compelling. rustdoc gives you a simple overview at a glance of what's actually in the public API. Discerning this from the source as a human isn't terribly difficult, but not as easy as a glance.
> but it seems to lack any and all facilities for non-refence docs, which most Rust projects basically don't have at all, some put in the top-level module docs (which usually limits the size)
Do you think every single Rust library should have non-reference docs? Some examples using my own crates: https://docs.rs/suffix https://docs.rs/suffix https://docs.rs/tabwriter https://docs.rs/tabwriter https://docs.rs/termcolor https://docs.rs/termcolor
I don't really think any of those are deserving of non-reference docs.
I do think I have some crates that would be deserving of non-reference docs but haven't been able to find the time to write them. It isn't for lack of tooling.
> a few have completely separated docs for anything non-reference
Do you see this as a problem? If so, why? Aren't non-reference docs, by definition, totally separate from reference docs?
> (Or one of the creative hacks to get around it, like creating empty public modules or useless macros to have additional pages).
I've used the empty public module approach before. Other than it being not quite an intended workflow, it has worked well. What specifically do you see wrong with it?
- formerly_proven 4y ago> * The actual public API isn't necessarily always obviously clear from the source code. For example, if you see 'pub struct Foo;', that doesn't mean it's actually in the public API of the library. rustdoc takes care of figuring out what exactly is exported. That's true, but hasn't really bitten me too much so far. In most cases it seems like if you managed to Ctrl+B some place and see "pub" it's probably actually public. The same goes for sorting by visibility in the structure browser, I'm assuming that just looks at the local visibility and not whether it's visible from outside the crate. It'd be cool if CLion could visually mark stuff that's not part of the crate API. > * Viewing it in a web browser has the benefit of it being nicely formatted. > * The web browser also has hyperlinks you can follow. Your editor environment probably handles a fair bit of these with 'goto definition', but the prose itself might have hyperlinks that aren't easily followed in the context of your editor. CLion/their Rust plugin renders doc-comments as inline rich text, complete with clickable references, so for these two points it's pretty much the same as rustdoc. In rustdoc I constantly get lost with more complex types because it's just a huge page which might have a lot of trait impls on it and if you're in the middle of it there really isn't anything telling you what you are looking at right now (e.g. whose trait methods). In CLion I have my breadcrumbs that always tell me where I am. Maybe sticky breadcrumbs would help with getting lost on larger pages. > Do you see this as a problem? If so, why? Aren't non-reference docs, by definition, totally separate from reference docs? Surely it means there is a lot more friction to doing it? You have to setup a separate documentation tool, builds and hosting for that, probably need to figure out how to configure it for linking into the reference etc. > Do you think every single Rust library should have non-reference docs? No, but to me it seems like Rust projects tend to have a lot less of it relative to other ecosystems. I've also seen a bunch of crates that don't have even one example in them, even though the code itself looked solid. > What specifically do you see wrong with it? It appearing as modules and navigation happening through the module table is kinda awkward but otherwise it's... fine? Which I suppose means that rustdoc is mostly there. - A general issue I've experienced with some crates is that (especially if there are only some API docs and nothing else) it's hard to get that "at a glance" overview of the API. Questions like "I wanna do X, what do I need for that" or "I have an X, and need a Y, how do I go from one to the other" aren't particularly obvious. It's often unclear to me from rustdoc (without trying to compile) what types can convert via From/Into into other types, particularly if crates bring their own variations of From traits into the mix. Doxygen used to do all these graphs, I mostly found them kinda useless, though the inheritance ones were sometimes useful. Rustdoc doesn't do anything in the visual-ish domain so far, which might be because that's proven to be a largely useless fad in prior tools, but perhaps Rust is sufficiently different from C++ that there could be more-than-useless visualizations. A concrete example where I sorta experienced this with the mysql crate. There's Queryable, okay, and you can see Conn implements that, so far so good. How do I get one of those? Conn::new is a thing, but that's a generic over "things intoable into some other type" (sorta Yoda-style as the "Opts: TryFrom<T, Error = E>" constraint). If I click on the TryFrom there that leads nowhere [1]. Clicking on Opts (apparently you can put trait bounds on non-type parameters, TIL) brings up the Opts page, and that has a little comment telling us to use OptsBuilder to make one of these. But there's also an inconspicuous "TryFrom<&'_ str>" down in the sidebar. The docs are silent on this, but that actually calls Opts::from_url, which is also not that documented but I can guess what it does. So now I've actually managed to figure out that I could have just done Conn::new("user:pass@host") all along (except that won't work because it wants mysql:// because URL, right? Maybe? I dunno, would have to try). Now, one might point out that the first lines of non-boilerplate in the example are this: let url = "mysql://root:password@localhost:3307/db_name"; let pool = Pool::new(url)?; let mut conn = pool.get_conn()?; And yeah, that totally gets you a Conn, right? Well PooledConn or whatever, but same difference. But I didn't want a pool, I just wanted to connect. I also can't click on anything in the examples (if I read this in my IDE, I actually can go to definition in all examples). Later it was time for writing some queries and of course the question became "well, uh, what types can I stuff in there? And when I query, what types can I convert to, and what does it expect for these on the other side?". Just from rustdoc itself this is difficult to understand (the 3rd question is of course not really answerable for rustdoc, as it lies outside the type system). There's actually a hand-written table to specifically answer these questions, but that's part of a dependency: https://docs.rs/mysql_common/latest/mysql_common/#supported-rust-types https://docs.rs/mysql_common/latest/mysql_common/#supported-... mysql actually has a very comprehensive overview in the crate root, it's just not directly see this as there is no table of contents for the contents of the page itself -- which makes sense for rustdoc, where, from the API docs PoV, you're not expected to put pages worth of content into a single module/struct/function docstring, but would be weird to be absent from a generalist documentation system. Headlines are anchors, so I'm guessing you can always create your own hand-made ToC here, but that doesn't seem ideal to me. People do that with README.md and it's not great imho. Just to clarify, I'm not trying to shit on mysql or mysql_common here, obviously. [1] I just thought that maybe if you build the docs locally with "cargo d" that it'd also generate std docs, but they only link to the online docs. "cargo d" also doesn't tell you where the built docs are and there isn't an overall index.
- burntsushi 4y agoRE browser vs reading the code: sounds like you have a nicer setup than my neovim setup. Although I think my first point still holds unless CLion handles that case too. With respect to the rest of your comment, indeed, those are issues. Although I think I take issue with you pinning this on rustdoc. I actually think it's a dance between documentation presentation (so, rustdoc), API design and familiarity with the language. I've long said that rustdoc makes unknown unknowns difficult to discover, and this is particularly painful for folks new to Rust. Because you don't really know what to look for yet. And writing docs is a difficult exercise in perspective taking, where you need to balance what you think others know. If you assume they know too little, it's not hard to end up writing too much and adding a fair bit of noise. With that said, I agree that "too little docs" is a far more common problem than "too many docs." But yeah, your experience is a perfect example of what I mean when I say "generics complicate APIs." They introduce indirection everywhere, and I'm not sure how much rustdoc can really help with that. You might be right that maybe there are some visualizations that can be added, but like you, I've always seen those as gimmicks in other tools that are rarely useful. IMO, a heavily generic API really requires the crate author to write more prose about how their APIs are intended to be used with lots of concrete examples. But that's really hard to do, because writing good docs requires being a good communicator, and most of us suck hard at that. The interesting bit here is that I've personally found the documentation experience in Rust to be far far better than any other ecosystem. All the way from writing docs up to consuming them. I've sampled many different ecosystems (C, C++, Haskell, Python, Go to name some) and other than maybe Go, I thought the doc experience was really just not great in any of them. Python specifically seems to be a case where I tend to see a lot of variance in opinion. I hated Sphinx so much, for example, that I built an alternative.[1] (Well, alternative for API docs, pdoc does not deal with the non-reference case.) I also just generally dislike the output that Sphinx produces. I find that it lacks structure, and I've always had a hard time navigating my way through Python library docs. [1]: https://github.com/mitmproxy/pdoc https://github.com/mitmproxy/pdoc