Improve format of Rust RFC, like Python PEP

Compare to PEP (Python Enhance Proposal), The format of Rust RFCs is much more informal.

  1. Rust RFCs are very unlikely to be updated, while PEPs are updated whenever its status changed (Draft, accepted, Final), with every post history included. It is not simple to know if any Rust RFC is superseded by another RFC, or abandoned, or feature implemented.
  2. With thousands of RFCs, there is no category to filter RFCs. There is a Active RFC List with category, but I do not find a link to the RFC markdown there.
  3. How to find the chat record how team members to reach consensus to accept a RFC?

I know that RFC is different with PEP.

PEP is often a formal reference, sometime with formal notation, in the same level of Rust Reference.

While RFC is informal with some initial thoughts.

But still is it possible to improve RFC, in the way that Python PEP does? For example, create a header similar to PEP

PEP 1 – PEP Purpose and Guidelines

Author: Barry Warsaw, Jeremy Hylton, David Goodger, Alyssa Coghlan

Status: Active

Type: Process

Created: 13-Jun-2000

Post-History: 21-Mar-2001, 29-Jul-2002, 03-May-2003, 05-May-2012, 07-Apr-2013

2 Likes

What pain point would this be trying to address? How are you “suffering” from the perceived downsides of the current RFC process? Can you give examples of where the RFC process/documents have fallen short for you?

2 Likes

Keeping the RFC texts more accurate is alternative to or complement of having a spec. A pain point I have encountered many, many times is that the existing documentation about the language is incomplete and/or incorrect, not to mention explicitly non-normative.[1]

Accepted RFCs are also not normative, even once completed (in large part because they are not kept up to date). However, they are still an invaluable resource for filling some of the holes in the documentation, or sussing out why something you've ran across differs from the Reference, say. That is, the RFCs are best source of information for some parts of the language.

But because they aren't reliably updated, you can't necessarily stop there. To get the full story you may have to read the RFC PR thread, read the tracking issue thread, search for RFCs that superseded this one, luck into finding any significant issues about the area of interest, and write a bunch of code to test out what the compiler actually does.

It's a lengthy process I've gone through more often than I wish, because I'm unaware of any better process to figure out what the compiler[2] actually does in depth.[3]

Below are a number of examples where the official documentation has been inadequate and the RFCs useful, but where the RFCs still fell short due to divergence or being superseded without the RFC being updated.

"That's the documentation process and/or specification process falling short, not a problem with RFCs" is a valid counterargument, provided that keeping those things up-to-date is a blocking requirement for significant changes (to stem this pattern from continuing to occur, once a spec exists :crossed_fingers:). Some mega-RFCs and many early-days RFCs are impractical to keep up to date in any case IMO (but could at least point the reader in the right direction).

Pattern binding modes

The reference is quite incomplete in terms of how binding modes work. In particular, it doesn't mention that the binding mode can be set to move at all, much less detail when this happens. But people do run into it happening.

To the RFC! ...hmm, it seems the reference accurately reflects the text of the RFC. Heck, the RFC is even explicit about it:

Note that there is no exit from the ref binding mode. This is because an &mut inside of a & is still a shared reference, and thus cannot be used to mutate the underlying value.

Also note that no transitions are taken when using an explicit ref or ref mut binding. The default binding mode only changes when matching a reference with a non-reference pattern.

What's the reality? From the middle of the 200+ comment tracking issue:

Changed from the RFC

The one change from the RFC was to "reset" the binding mode to "by value" whenever you encounter an explicit & or &mut pattern. This is to resolve the confusion described in #46688.

(While looking up the tracking issue, I also noticed the final comment contains another example of something from the RFC that does not compile, currently tracked by this separate issue it seems.)

I can only assume the reference is incomplete because it was based on the RFC text.

Understanding NLL in depth

This is a case where the RFC is invaluable. Nothing else explains how intrafunction borrow checking works without glossing over a ton of details, and usually conflating lifetime regions with value scopes, which the RFC takes care to avoid. It's also one of the only official places to find a definition or even mention of reborrowing (!).

That said, the RFC is arguably more useful to explain why certain things compile, versus fail to compile. Most programmers are more concerned about the latter. Leading to...

NLL Problem Case #3

People run into this one a lot, and allowing the code was one of the goals of the RFC, but it hasn't happened yet. But you can't read the RFC alone and find that out. No other documentation goes into borrow checking in enough depth to help you out either.

There's other deviations from the RFC too, but I couldn't tell you exactly what they are.

Two phase borrows

As far as I know it's not in any official documentation, so again one needs to fall back to the RFC to explain why certain code passes borrow check.

However, how two-phase borrows was actually implemented expanded beyond the RFC as outlined in this future compatibility lint issue. That lint was eventually abandoned (the warnings allowed) in order to land NLL stabilization.

I couldn't tell you exactly what two-phase borrows allows without doing a ton of work (experimentation and whatnot).

See also.

Breaking Changes

What should constitute a major breaking change? As far as I know, this topic also isn't covered in the standard documentation, so this is another case where the primary documentation is in an RFC. However, when it comes to traits, there's a distinction between fundamental and non-fundamental traits. Implementing non-fundamental traits is only a minor breaking change, it says.

But actually, it is a major breaking change if it's a blanket implementation.

Finally, RFC #1105 states that implementing any non-fundamental trait for an existing type is not a breaking change. This directly condradicts RFC #1023, which is entirely based around "blanket impls" being breaking changes. Regardless of whether the changes proposed to the orphan rules in this proposal are accepted, a blanket impl being a breaking change must be true today. Given that the compiler currently accepts impl From<Foo> for Vec<Foo>, adding impl<T> From<T> for Vec<T> must be considered a major breaking change.

As such, RFC #1105 is amended to remove the statement that implementing a non-fundamental trait is a minor breaking change, and states that adding any blanket impl for an existing trait is a major breaking change, using the definition of blanket impl given above.

Unfortunately RFC 1105, at least as it exists in the RFC book, was never updated. This can be problematic when people refer to RFC 1105 to reason about what is or isn't a major breaking change. That's a liability to Rust's stability guarantees, not just an inconvenience for Rust programmers.[4]

This example illusrates that a spec alone is inadequate; if the RFCs aren't going to be updated, there needs to be an official place for things like this (and probably things like the governance RFCs) to be documented and kept up-to-date.

Others

I'm getting tired of writing these up and you've probably been tired of reading them for awhile, but other cases I've personally ran into where the reference was inadequate and the RFCs also incomplete or out of date include


Personally, the vast majority of my gripes would be satisfied by an accurate living spec.[6] I'm very happy the spec RFC was accepted and deeply hope it comes to be.

In the meanwhile, I feel the OP's pain.


  1. The std documentation tends to fare better. ↩︎

  2. and so in a sense, the language ↩︎

  3. I guess becoming an expert in the compiler itself is an option, but not one users of the language should have to fall back to. ↩︎

  4. Tangentially, future compatibility lints assert they will become a hard error, but sometimes the plan is to allow them; this can be problematic if other developments take the assertion at its word. ↩︎

  5. including a number of "only partially implemented" ↩︎

  6. Especially if the RFCs also got updated with helpful notes in the event of significant changes like here and here and here, etc. ↩︎

14 Likes

Oddly, enough, this is captured in the cargo book, see SemVer Compatibility - The Cargo Book . We have a tracking issue for improving it.

2 Likes

@quinedot's description very much matches my experience of trying to understand the language accurately — both for myself and to be able to point others to documentation answering their questions. Just yesterday the only concrete information I could find about promoting temporary values to statics was the original RFC 1414 — and it's wrong, or at least, doesn't mention one of the conditions under which the compiler doesn't promote. (I still don't know what condition that is, and would have to perform experiments to find out.)


If I were in charge, the cheap change I'd make is to decree that RFCs may be expanded with “note” paragraphs that describe what has been implemented, changed along the way, or been superseded by later RFCs. These notes would be considered not part of the RFC text per se (thus avoiding misleading anyone about what was approved in the past), and not any kind of reference documentation (they do not need to be complete, or maintained when things change further) — they would be focused on providing pointers forward in time, as people see fit to write them.

5 Likes

We do this occasionally, like Add a note to 2115 about un-accepting in-band by scottmcm · Pull Request #3219 · rust-lang/rfcs · GitHub

While I understand the desire to not edit through the RFC text, we should at the very least get way better about adding these sort of clear "from the future" warnings about things that aren't true anymore.

1 Like