-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
RFC: rustdoc meta tags #1713
RFC: rustdoc meta tags #1713
Conversation
one alternative for function arguments and return value is to add doc comment directly to the argument/return type. |
Another alternative is to go the Swift-way, i.e. use special headings and formatting that rustdoc will have knowledge of. Which has the nice property that this will still look fine when seen as plain markdown and rustdoc doesn't have to care about it to render it nicely. For example: /// Fooify a `Foo` with a label
///
/// # Parameters
///
/// - `label`: A string labeling the foo
/// - `magic`: A `Foo` that will be labeled
///
/// # Returns
///
/// A `Result` which is:
///
/// - `Ok`: A `Bar` that is the labeled `Foo` and thus lives as long as the
/// `Foo` given in `magic`.
/// - `Err`: Returns the number of gravely appalled people (per half-century
/// per country) if you were to use that label *and* `Foo`'s acceptance
/// indicator is less than it.
///
/// # Lifetimes
///
/// - `floof`: The life time of the given foo as determined by the floof source
/// it was originally loaded from.
///
/// # Examples
///
/// ```rust
/// assert_eq!(fooify("lorem", Foo::extract_from_global_floof_resource()).label(),
/// Bar::with_label("lorem"))
/// ```
///
fn fooify<'floof>(label: String, magic: Foo<'floof>) -> Result<Bar<'floof>, i32> {
unimplemented!();
} Validating and parsing this might be more difficult than using new, explicit syntax, though. (Updated example to use A few more notes: https://scribbles.pascalhertleif.de/machine-readable-inline-markdown-code-cocumentation.html |
Javadoc has a similar setup to what's proposed: /**
* @brief some short description
* @param foo A foobar
* @returns blah
*/
Blah doFoo(Foobar foo) { ... } |
I know many other languages offer such a facility (e.g., Javadoc as mentioned by sfackler). I think this RFC would benefit from a survey of what other languages offer in this space and what we should/shouldn't copy. |
This might go a bit too far, but: Is there a plan to expose this kind of structure documentation in a machine readable way? I assume the AST currently only gives you one There are a few things we can do:
Another point: I would also expect there to be a clever lint that can find errors in those doc strings (like misspelt parameter names). This lint and AST extension I described would need to be part of rustc (not rustdoc) to be useful, so it couples the doc syntax with the compiler. This is another drawback that will need to be mentioned in the RFC. |
This is similar to the idiom in the standard library today. I personally find it painfully verbose to navigate in a text editor. |
There already are some tricky bits about dealing with arguments, since they can be patterns; there can be dummy arguments: fn foo(_: i32, _: i32) -> i32 { 0 } As far as I can surmise these seem unlikely to be a major concern, since if an argument is worth documenting, then it must also be worth naming. (with a Another thing is that the most comfortable way to write arguments for implementation may differ from the most comfortable way to document them: type Point = (i32,i32);
type Vector = (i32,i32);
fn displacement((x1,y1): Point, (x2,y2): Point) -> Vector;
fn displacement(from: Point, to: Point) -> Vector; The first function above is more comfortable to implement---but when it comes to documentation (either writing or reading it), I would sincerely hope for the latter! |
Also, do we call them "arguments" or "parameters?" I think after a while of using rust I have come to associate the word "parameter" with "type parameters." |
Regarding the pattern matched arguments and the difficulty in naming them, I see two options: either naming them by position and/or through a use of named parameters (a potential feature, not one implemented yet or RFC-d yet). Regarding the RFC itself, I think I prefer the Swift way more than Java's |
Hm, reading it more closely now I see the proposal is quite specifically about That said, I imagine that other tooling such as IDEs would also be interested in metadata like this, and could probably benefit significantly from strict requirements on the syntax. |
@ExpHP on parameter vs argument There's actually a technical definition :) http://stackoverflow.com/questions/156767/whats-the-difference-between-an-argument-and-a-parameter fn foo<'a, T>(t: &'a T) {
...
}
foo::<String>(&String::new()) the lifetime of the call expression is the (hidden) lifetime argument, |
That's a good point! I feel like it's only a minor inconvenience, though. Many editors/IDEs allow you to jump to a symbol (and Rust code is very grep-able) and collapse functions/doc comments; I would also say that parsing a doc comment in the style I proposed is far easier for a human (you can visually move from headline to headline as they are separated by empty lines, instead of the keywords after an '@').
Indeed. I would expect the the doc syntax to support basically everything you can write on the left hand side of the parameter, though, as long as it's unique. So, e.g., |
@ubsan But we already have formal vs actual for that, which are much more precise. I prefer to use "argument" for "(non-constant) value parameter" instead, which is orthogonal to formal/actual. |
@eddyb That's not how it's defined. Argument and parameter are both very well defined terms... https://msdn.microsoft.com/en-us/library/9kewt1b3.aspx
https://en.wikipedia.org/wiki/Parameter_(computer_programming)
|
I agree that Swift has improved a lot in this space. Their metatags aims to help not only in standard docs but also to help IDE tooling providing information for code completion, besides being markdown based. |
I like the alternative @killercup has proposed far more than the original. |
@jimmycuadra so we talked about this at the docs team meeting today. It seems like most people are not concerned about this idea in general, but aren't super happy with the |
The higher order bit is this: if we can get something that's closer to standard markdown, yet semantic enough through a convention, that would be preferable to inventing some kind of new syntax, basically. |
I'm not married to the @ syntax, personally. Using a more free-form style like @killercup's example seems fine to me, too. The only concern that comes to mind is whether it would be difficult or error-prone for rustdoc to interpret that style correctly. The @ syntax seems easier for a program to parse, but of course documentation should be optimized for people, not machines. |
I think it will be more difficult to parse than @jimmycuadra By the way, feel free to use anything I wrote here (and in this post) in your RFC (if you want to rewrite it) – consider it licensed under CC0! |
What's the procedure for revising an RFC that drastically? Do I just push a commit that changes it, or create a new PR and close this one? |
Why not support both? The two formats do not have any conflicts... Many are used to the java, javascript, php (https://www.phpdoc.org/), c++ (http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html), ruby (http://yardoc.org/features.html) way of documentation. And these languages make up a large chunk of the langs all developers use.
|
So, interestingly enough, this is actually something that the new changes to the RFC process are hoping to address: people come together around a problem (the motivation), then figure out in a broad sense what strategy should be taken, and then end up submitting an RFC. Anyway, we're not there yet, but just a thought. You can do either of those options; I personally would open a new RFC and link to this one as a comment on it.
Because supporting both is not free. You have to support and maintain both kinds of parsers, as well as splitting the ecosystem. |
Granted that is not free - but is the cost really that great? Looking for a limited set of predefined strings all beginning with "Splitting the ecosystem" is one way to put it, "freedom of choice" is another... Why enforce one way over another when it is quite subjective? The |
Having one format means:
Even though this is Rust, I personally enjoy languages that follow Python's principle:
|
|
I will revise my RFC and create a new PR with the new approach and then close this one. If people have more thoughts on the topic, feel free to keep commenting here until then, of course! |
Thinking about this more, I'm less sure how rustdoc would behave if any of the special sections contained content it didn't know how to format. For example, what would it do if the parameters section contained two different lists separated by some free-form text? What would it do if there was one list, but one or more of the list items did not begin with something it could identify as a parameter name? |
My opinion – just one way of dealing with this, as written above:
Concretely: Don't treat it as a valid section, i.e., ignore it. Have rust{c,doc} print warnings using the lints I mentioned above. |
@killercup In the "returns" section example in your first comment, which part of that format do you imagine being required by rustdoc? I'm referring specifically to how it starts with the freeform phrase "A |
@jimmycuadra, very good questions! I'll try to address them one by one. I wrote a semi-formal description of each section (and how to parse lists) here, by the way.
The "Returns" section is the only one that does not need to contain a list, as any function or method can only ever return one (generic) type. Thus, only the freeform text is required (an empty section would be useless). The only limitation on that freeform text is that it can't contain a list, as the only list that is allowed to follow it has to be an enumeration of enum variants of the return type. I felt like this was the most common case, but thinking about it now makes me to suggest a better, more general way: Instead of matching the enum variant names, we should allow arbitrary patterns. This way, it will be possible to describe all possible variants of a return type like
I don't think this is a good idea for human readability, but I can see where you are coming from. As I mentioned above, from the 4 sections I proposed, only "Returns" doesn't need to have a list. It might make sense to use a list style for "Panics" as well, but for all other sections I would not enforce it.
For "Examples" specifically, I would use subheadlines instead of lists as nesting code blocks in lists is pretty weird. I don't see a use case for mapping descriptions to examples; what did you have in mind?
I think it would be helpful to define a set of goals/properties we want to extract from doc comments. It might also be useful to write a POC markdown parser and combine that with a bunch of example files to see how hard it actually is to extract this information. |
I am curious why nobody has yet mentioned RFC 1574 which introduces "certain conventions around documenting Rust projects". It defines some general conventions like using line comments and English as the language but also introduces six well known top-level headings:
These match @killercup's proposal and could be extended with headings for parameters, returns and lifetimes. Some sections may have a special syntax like a list for parameters. By the way it would be great if rustdoc highlighted the already defined sections in the output. |
@pyfisch Oh, I meant to link to #1574, but I see now that I only did that in my post, not in a comment here.
What do you mean by this? Highlight how? The headlines are rendered as, well, headlines. Would you like a special style for section with special names? I think this would be a bit confusing; we should enhance the output where it makes sense (e.g., render parameter lists in a special way to include the type names), but not render stuff differently 'just because.' Actually, I don't have a good idea how to change rustdoc's output based on this structured information (aside from the parameter list, and maybe adding tooltips). It will be great to see editors/IDEs use this information for contextual information, though. |
I’m personally strongly against this RFC¹. I will not use any of these attributes, will reject all PRs to my own projects using any of them and will go as far as forking rustdoc if using such things would become a necessity with the rustdoc. ¹: Having used JavaDoc and Doxygen, I hate both of them (or rather format they use). Let me explain why:
|
I strongly agree with @nagisa on that these attributes wouldn't be the way to go. I've had quite a few unpleasant experiences with Javadoc/XMLDoc/Doxygen where I was just going through the motions adding "file is the file that's being processed" and "returns the resulting value" to everything. I think that the current situation is working fine and there's no need to add meta tags. I haven't seen or personally had a need to define documentation on a more fine-grained level than what rustdoc currently provides. The one situation I can see where these would be of use is in IDE integration, but in that case the IDE can just provide the function's doc. The big question I really have is, what problem does this solve? The RFC mentions consensus on how to provide docs, but we have a decent consensus so far that's been used throughout the community of providing a brief explanation of the function. |
I disagree with @nagisa on param/return. As a illustration, this was on my twitter timeline at random, today:
Besides docs, what I'd really like to see would be the opportunity of having code assistance containing docs. These tags (or any solution in this sense) help on that. Avoiding code roundtrips to check docs for then, write correct code. Code completion, intellisense, etc, aims to deliver you that while you're coding. Free form documentation of the entire function is unnecessarily longer than the much shorter documentation of the actual parameter you're about to fill. I'm not sure whether anyone has attained the best solution in this realm, but for me as a whole, this kind of feature is useful. Beyond that, Swift goes further making it even more documented at call site by actually having named parameters, so when you read the code you can actually read what is One may argue that by having such features a language is welcoming anti-patterns (for which the sole one I can think of is long parameter lists) and hence to prevent that, a language should avoid it at all, just to make it more difficult to have long parameter lists. I don't like long parameter list too, but, like in the image above, even for a short prototype of two parameters, if you don't know what's |
FYI, I was bored and after playing around with pulldown-cmark wrote a simple parser for doc strings in the format I described above. Nothing really fancy, just as a proof of concept. You can see the code here: https://github.com/killercup/rust-docstrings |
ping @jimmycuadra @steveklabnik status? |
I don't think I'm going to have time to work on a revised RFC for this anytime soon. What's the protocol? Just close the PR? |
If you don't have time to work on a revised RFC any time soon; I vote that we should close as "postponed." This isn't a judgement on the validity of the RFC, and if anyone else wants to champion this at a later time, they can do so. Thanks! |
Rendered