Pre-RFC: Stable rustdoc URLs

I didn't think of traits; that makes t a neat way to avoid the issue altogether :smile:

1 Like

Yeah, if we combine this with your "omit the prefix for the value namespace" idea, it becomes:

  • t.Name.html for traits and types (haha convenient), and theoretically modules, which are in the same namespace, except not actually because modules are subdirectories instead (haha convenient x2)
  • m.Name.html for macros (seems fine)
  • name.html for fns and NAME.html for consts and statics (seems fine)

which seems pretty reasonable.

4 Likes

Ok, I updated the post to use t.Name, m.name, and name respectively (with a mention of type. and macro. in the alternatives section). I also opened https://github.com/rust-lang/rust/issues/76922 and moved most of the naming conflict section there.

1 Like

Another reason to not have a v. prefix is that the URL would be longer and noisier. Functions and values are very likely more common than types/traits and macros.

My personal experience is that I spend vastly more time looking at struct pages than at all other item pages put together. I'm technically looking at functions when I do that, but most of the important functions in Rust are struct methods.

Either way, I think it makes sense for Unicode mangling into URLs to use punycode, as it's already used for domain names. (I'm not sure how browsers treat punycode not in the domain, however; they're probably required to not demangle outside of the domain name. But also they're moving away from showing anything other than the domain anyway, so...) Unfortunately, punycode (by design) is no help in encoding ASCII case information.

(edit after later post: @jyn514 sorry, my bad.)

1 Like

Could you please move discussion on avoiding name collisions to the issue? These are great ideas but they're not super relevant to the RFC. https://github.com/rust-lang/rust/issues/76922

I posted an RFC: https://github.com/rust-lang/rfcs/pull/2988. Thanks to everyone for the feedback, especially @elidupree and @dhm for getting some of the name bikeshedding done early :wink:

2 Likes

Is that really semver-compatible though? Doesn't it break pattern matching? Even structs Foo, Foo(..), and Foo { .. } are different in that regard.

Hmm, the specific use case in https://github.com/rust-lang/rust/issues/55160 was switching from a union to a struct. Can you pattern match on unions?

Ooooh, that is nasty. Even with all private fields, this code compiles:

mod foo {
    pub struct Foo {
        field: i32,
    }
}
use foo::Foo;

fn fooer(foo: foo::Foo) {
    let Foo { .. } = foo;
}

and thus Foo can't be changed into an enum without breaking compilation. (It can be changed into a tuple-like struct, though, oddly enough?) I haven't thought of an example that prevents union->struct or union->enum though. And even enum->struct might be possible if the enum's variants were all #[doc(hidden)].

Regardless, at the very least, it's clearly compatible to switch an item from any concrete type into a pub use or a type alias to that type. So we definitely need this RFC for something, and it doesn't seem especially valuable to try to preserve the URL naming distinction between struct, enum, and union.

1 Like

it's clearly compatible to switch an item from any concrete type into a pub use or a type alias to that type

Oof, I knew I forgot something. I don't think rustdoc generates pages for type aliases currently, to support this it would have to.

It does - for example, https://www.nalgebra.org/rustdoc/nalgebra/base/type.Vector2.html

1 Like

It's unsafe, but otherwise yes: https://doc.rust-lang.org/reference/items/unions.html#pattern-matching-on-unions

Huh, I didn't know that worked!

1 Like

…but since pattern matching on unions is only possible if you specify exactly one field, it is not possible for dependent crates to pattern match on a union with no public fields, which preserves the possibility of semver-compatible conversions from union to struct or enum.

2 Likes

There seems to be one more class of semver-compatible, but possibly link-breaking changes - replacement with reexports. There are at least a few kinds with different amount of problems caused

pub fn my_fn() { ... } // Before
pub use self::submod::my_fn; // After

pub fn my_fn() { ... } // Before
pub use self::submod::*; // After

pub mod my_mod {
    pub fn my_fn() { ... } // Before
}
pub use self::container_mod::my_mod; // After, container_mod definition elided for brevity

pub mod my_mod {
    pub fn my_fn() { ... } // Before
}
pub use my_helper_crate as my_mod; // After :-)

Note that some of them would require replicating whole subtrees if all links are supposed to be stable, possibly even cross-crate.

This is covered in the section 'Re-exports will generate a page pointing to the canonical version'.

It will be a larger number of pages, but each individual page will be very small.

1 Like

IMO it would be a good idea to match the namespaces the way they work in rustc also as a slight hint for how names work in rustc -- answering questions like "why can I have a function and a type of the same name but not a trait and a type of the same name".

So :+1: for this proposal:

What should be done for things like tuple structs that are both in the type and value namespace?

That is a good question... from a purely technical perspective, I'd say both files should exist, likely with one redirecting to the other.

(They exist in both namespaces but really these are different components -- the thing in the value namespace is the constructor. This is similar to enum variants which also have a constructor in the value namespace.)