If there is no data attached to any of the variants of an enumeration and
there is at least one variant then it is called a c-like enumeration.
This name is terrible. It’s referring to the C programming language’s construct of an enum and that in some cases[1] can be passed to C for FFI. But in reality, it’s also useful in non-FFI code. You also have to know C’s enums to understand the name.
As such, I propose renaming this term to something more meaningful.
@scottmcm suggested discriminant-only enumeration on IRC when I asked last night. Though I open this up for bikeshedding.
[1]: Specifically, when the enum has a C representation.
To add another reason why this name is misleading: A C enum is mostly a typedef plus some named constants, i.e., an object of an enum type can hold any integer value. This is often used for bitflags, for example. In contrast, Rust’s C-like enums (even those with repr(C)) can only legally hold the discrimnant values, everything else is UB. Therefore, using a C-like Rust enum in FFI to model a C enum is often outright wrong and risky even at best.
“discriminant” sounds very much like techno jargon to me. I haven’t seen that term used outside compiler-related discussions, so I doubt it’s any more informative to average user than “C-like”.
The gotchas with #[repr(C)] are real though. Maybe instead of changing the name, the UB should be removed instead? (i.e. a C-like enum with #[repr(C)] should really behave more like C).
Can’t be done in a sound, backwards-compatible way. You can match on a #[repr(C)] enum exhaustively, and if you do that then you can have the match expression evaluate to any type:
#[repr(C)]
enum Test {
A = 1,
};
let test: Test = unsafe { transmute(3) };
let result = match test { A => 2 };
println!("{}", result);
What should the above code do? Because right now, it compiles and it invokes UB.
AFAIK UB here is by Rust’s implementation choice, and can eliminated by arbitrarily defining how other values are interpeted (for example, that the last match arm is taken). There’s no way to make it sensible, but at least it doesn’t have to cause nasal demons.
immediate enumeration (a reference to compiler-slang using “immediate” for scalar values.)
numeration (these enumerations are isomorphic to an integer interval [1; n], except that names are more readable than hardcoded numbers)
(You can also use simple/flat/immediate for constructors/variants: a flat constructor takes no parameters, and a flat enumeration has only flat constructors.)
In type theory we say “sum type” for the disjoint-sum construction that underlies variants, and in ML languages we say “variant type” for what is called in Rust an “enumeration” (which is a sum-of-products type).
(Why is there a special requirement that c-like enumerations should have at least one variant? What goes wrong if we have empty c-like enumerations with no variants?)
#[repr(C)] discriminant only enums are not necessarily the same size as the equivalent C enum. Even when they are the same size, holding any value other than the defined variants is UB, unlike the equivalent C enums which are often used as bitflags. Using Rust enums in FFI bindings is generally a bad idea.
Therefore I am strongly in favor of moving away from the “c-like enum” terminology.
We had a quick chat about this idea at today’s docs-team meeting. Of the suggestions so far, we seem to like either “plain/simple enums” or “data-less enums”/“enums without fields”. The latter is pertinent because it was mainly proposed in terms of removing the need for a fancy name altogether. Enums are enums; some have fields and some do not. The ability to set numerical values to the discriminant in these enums is just a property of not having fields. (Or “data”, or whatever we’ve decided the general term for values other than the discriminant enclosed in an enum variant is.)
So, i guess, the options we’re narrowing it down to are:
“simple enums”, as a subset of “enums”
“enums with fields/data” as opposed to “enums without fields/data” (with “field-less”/“data-less” as a shorthand)
If it were strictly between those two, what would you pick?
“data-less”/“field-less” (and their longer forms where more appropriate) strikes the ideal balance for me - it’s simpler and shorter, without needing the reader to figure out what “simple” actually implies (not that it’s a particularly hard one to figure out with minor context, but it still seems slightly worse than the term which outright says what it means)
Why does this even need an official name at all? We don’t call enums that benefit from NonZero “nonzero enums”; Rust does all sorts of enum optimizations under the hood, why privilege this one?
If we must call it something, avoid jargon like “discriminant” at all costs. “Simple enums” would suffice.
I personally avoid terms like “simple” and “plain” to describe anything because they aren’t really self-describing. Granted, that’s an improvement over a misleading name.
We want a name for it because they interact with other features (e.g. casting to integers) in ways that enums with data do not. They need at least one variant because those without variants are called zero-variant enums, and want to avoid creating inheretance hierachies in names.
+1 for c -like enum, though i see that only the first few have some votes gotta go now because i need to check the site. said i need to take bcuz of my health problems. but i will come back with some questions. about some of them. could you help??