Back in the day it was necessary to do
enum FooInner {
A,
B,
}
pub struct Foo(FooInner);
Is this ergonomic thorn still necessary?
Back in the day it was necessary to do
enum FooInner {
A,
B,
}
pub struct Foo(FooInner);
Is this ergonomic thorn still necessary?
If you wish to make the variants private, yes.
ugh is this thorn ever gonna get fixed
what's even the point of this thorn anyway. what benefit does it have.
If you feel this passionately about it, you can always write an RFC for some mechanism to make all enum variants private.
As a historical note, this feature was removed by RFC 26; before that, one could use the priv
keyword to create private variants in public enums. Most of the discussion around the change occurred in the issue rust-lang/rust#8122.
in an ideal world you'd be able to treat enums as "just another form of type". as they should be.
why do structs get encapsulation at all if enums don't? why do you have to newtype your enums? this pattern exists a lot in std and it's awkward having to wrap and unwrap everywhere simply because the compiler doesn't provide these with first-class support for encapsulation.
also we don't even want "individual variants" we want straight-up all-or-nothing.
I have indeed felt this, and wonder if some visibility modifier like
pub(notimplied) enum Foo { PrivVariant }
Which flips the pub
default on variants to priv
, keeping the ^^^
pub not permitted here because it's implied
type of errors. So still disallowing mixed visibility enums.
I don't think pub(notimplied)
is particularly good name, but
It looks like the discussion on that RFC was generally in favor of [1] a way to make all enum variants private, so an RFC for a way to do that (as opposed to marking individual variants private) might be accepted.
I agree that wrapping with a struct for this feels a little goofy.
Maybe something like pub opaque enum Foo
for enums that should be treated like a struct with private fields?
or at least not AGAINST âŠī¸
It would have been nice if the default for variants had been private, same as for fields in structs. Then presumably this would be possible:
enum Foo {
PrivateVariant
pub PublicVariant { priv_field: String, pub pub_field: u8 }
}
Presumably it could even be done with an edition, using something like rust fix
or other tooling eg RA to autoconvert the code.
However, there could be drawbacks that at present I'm not aware of.
as a workaround, we could have macros like encapsulated_enum!
and encapsulated_match!
in a library crate, which just abstract away all of this stuff, maybe?
You could probably create a custom #[private_enum]
attribute which generates the wrapper struct plus a #[doc(hidden)]
implementation for Deref
so pattern matching on references still works inside your crate.
I was just yesterday trying to talk about having a type alias that doesn't leak the aliased type but doesn't require you to have .0
everywhere in your crate like a newtype. At least part of the problem is that "opaque type alias" as a phrase got stolen by "type alias impl trait" (TAIT).
So yeah, bring back priv
wouldn't Deref leak?
that's what Self(self)
would be for ("destructurable self" maybe?), but you'd still end up putting Self(foo)
everywhere.
Kinda? I don't think it would be an issue in practice.
If the Deref
impl is #[doc(hidden)]
then it won't be visible in API docs. Similarly, because FooInner
isn't exported they have no way of naming the type (or its variants - so match
won't work). The only way details can be leaked are if the user calls public methods on the enum (of which there should be none) or trait methods (which they can only find out by reading the source code, anyway).
<Foo as Deref>::Target::Variant
because you'd need the enum to be pub
for that.
Yeah, the enum would have to be public for Deref
to work.
we feel like
opaque_enum! {
pub(in path) Foo {
Variant, ...
}
}
impl Foo {
fn foo(self) {
opaque_match! {
self {
Foo::Variant => { ... },
...
}
}
}
}
would be the best workaround for this use-case.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.