Non_exhaustive for modules

We noticed that this:

#[non_exhaustive]
pub struct Foo;

is unlike this:

pub struct Foo {
 non_exhaustive: (),
}

and more similar to this:

pub struct Foo {
 pub(crate) non_exhaustive: (),
}

As such, we'd like to see #[non_exhaustive] disappear in Rust 2024, and be replaced with #[non_exhaustive(crate)] and #[non_exhaustive(self)] and so on. (We'd strongly argue the default should be module-local, but for consistency with pub we'd suggest deprecating it entirely because a fully-public non_exhaustive should have no effect. Obviously being able to specify (self) or (crate) should be available on all editions.)

1 Like

I think the default should remain crate local. This would not require deprecating #[non_exhaustive] without an export level specifier. In addition the rationale for making it crate local from the RFC still applies IMO:

Within the crate that defines the enum, this attribute is essentially ignored, so that the current crate can continue to exhaustively match the enum. The justification for this is that any changes to the enum will likely result in more changes to the rest of the crate.

[...]

Like with enums, the attribute is essentially ignored in the crate that defines the struct, so that users can continue to construct values for the struct.

2 Likes

For an application crate, module-level scoping is extremely powerful. But if it's not a valid Rust use-case that's okay too we guess, just annoying.

We do think encapsulation is awesome and Rust should expand its encapsulation options tho. And you can always just use #[non_exhaustive(crate)] if you don't like it.

1 Like