-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Privacy for enum variants and trait items #2028
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
Conversation
Marking non-exhaustiveness with a dummy variant seems like a step in the wrong direction to me. It feels weird. One of the reason it feels weird to me is that I have trouble imagining a case where this is useful for things you actually want to match on. Is it possible to show extant code where matchable private variants would be helpful? |
From the RFC: pub trait Trait1 {
fn method1();
pub(crate) fn method_without_default();
} This feels strange to me. Under this RFC, the "package private" method here is |
You can read |
I think the issue being raised is that Especially since it can easily muddy the waters and side-track someone into wondering whether TL;DR: It's bad for teachability if you have to explain that to everyone who concluded that |
Oh, I get your point now. The issue is that the defaults are swapped here. Struct members are private by default while enum variants and trait items are pub by default. That's a valid point. |
Maybe we could require explicit |
@glaebhoerl To be honest, that really screams "we wanted this so badly that we're making a hack everyone will recognize as ugly in order to circumvent our backwards-compatibility requirement". In fact, that "you've gotta retroactively annotate all your old variants/items with default behaviour in order to start annotating non-default behaviour" pattern which appears nowhere else in the language feels like enough of a hack that I worry people I'm teaching/mentoring might count it against my credibility as an experienced authority unless I explicitly throw the language under the bus on that point as part of teaching them. |
To be clear, I think inherited privacy for |
You could add a |
|
|
We can change the default in a Rust 2.0 future, and requiring it just in the types using the new features is fairly small churn. I think not doing things simply because they are deemed to give impression that we're admitting mistakes is rather obnoxious. Better to come clean than sweep under the rug. |
I'm not by any means saying that admitting to a mistake is bad. I'm saying that, from my perspective, the " If |
I don't think it's a mistake, so far this scheme served us with almost no complaints, and this is indeed what you want in most cases. |
I'm still waiting for that example of a public enum in existing crate that would benefit from non-public variants. :) |
Please, wait some more, I haven't even looked through all the comments yet! Do you mean in addition to exhaustiveness checks? I can imagine cases when private variants could be useful. For example the enum is a state machine with some states that can be observed externally, and some states that are purely internal/intermediate. |
My primary argument in support of the private variant idiom is that making non-exhaustive enums is not a dire everyday need and doesn't worth extending the language, there's just need to be some way to do it. |
Not going to bother finding a crate with such a situation, but here's a very plausible example: You could make use of an pub enum Source {
Utf8(String),
Binary(Vec<u8>),
pub(crate) PartiallyUtf8(Vec<u8>, usize),
}
pub fn encode(src: Source) -> EncodedString {
}
fn grow_and_encode(s: String, more: &[u8]) -> EncodedString {
let index = s.len();
let mut vec = s.into_bytes();
vec.extend_from_slice(more);
encode(Source::PartiallyUtf8(vec, index))
} |
I've kinda wanted non-public variant several times. I even learned the private-in-public when trying to create them. I run into them when trying to use a polymorphic That said, I think non-public variants look weaker than being able to circumvent the private-in-public rules, so maybe one should work towards that instead. If there was a
I could use this enum in several ways : I can use it for internal state. I can pass it in as a configuration option, usually using the two You might argue against abusing polymorphic tl;dr I think the case against non-public variants is ultimately stylistic and subtle, but I also think mechanisms for breaking the private-in-public rules look more powerful. |
If this RFC establishes the |
#2008 was merged, so I'm closing this as not having sufficient motivation. |
@petrochenkov I don't understand how #2008 solves the issues raised by this issue, in particular as it relates to |
@petrochenkov I'm running into a situation where |
@jhpratt could you do something like this? pub enum Foo {
Bar(...),
Private(Private),
}
pub struct Private {
fueld: Quax
} This way users can't construct the variant if they never see the variant. |
@KrishnaSannasi I could, but as I mentioned in my previous comment, it's easier to add an |
Another motivating example would be // where each variant represents some string
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub enum EventKind {
One,
Two,
priv Custom(String), // look priv is red, github already knows it should work XD
}
impl EventKind {
pub fn only_way_to_access_custom_that_wont_break_forwards_compat(&self) -> &str { ... }
} So if the user of If adding a strange keyword is hacky I would argue |
I would still like to see this. enum MyThingImpl {
A(...),
B(...),
}
pub MyThing {
state: MyThingImpl,
} Is an ok workaround but it is very unergonomic. Now I need to add I think there should be a way to use an Right now users are forced to pick between |
what about separately considering |
I agree that |
Well every issue about this that I am aware of hase been closed. So should we reopen one or open a new one? |
The best path forward would be to draft a new RFC proposing the changes. You could open a new issue for that until the RFC is done, but there's also the internals forum, Zulip, etc. for posting about it as well. |
Filed #3506 |
Support
pub
/pub(restricted)
on enum variants and trait items, it helps with controlling matching exhaustiveness and trait implementability.cc rust-lang/rust#32770 #943 #2008
Rendered