<p>In Java, enum values behave like objects (<a href="https://softwareengineering.stackexchange.com/questions/301542/understanding-enums-in-java">since they are basically syntactic sugar for objects</a>) and they can have their own class methods. In C++, however, enums are essentially an alias for an integer constant.</p>
<p>What are some possible situations where a Java type enum would be better/make more sense to be used and when would a C++ enum make more sense in a language?</p>

<c++><java><enumerations>
When would a Java style enum be better than a C++ style enum, and vice versa?
CC BY-SA 4.0
2023-07-26T15:42:37.063Z
There's a third kind of enum: sum types, as in Swift and Rust.
Bbrk24
CC BY-SA 4.0
2023-07-26T15:51:32.410Z
Also, Typescript's enums can be string constants, not just integers.
kaya3
CC BY-SA 4.0
2023-07-27T04:25:59.193Z
... and then there's C#, which provides a C++-style enums, but allows to use extension methods on them. TBH you can even use extension methods on "primitive" types in C#, and that's one of the reasons I changed my mind about C# after 3.0
user213769
<p>C++ enums are essentially just <code>int</code> constants.  This makes them efficient to implement, and usable for low-level or performance-critical programs.</p>
<p>OTOH, Java-style enums have full <code>class</code> functionality.  They provides better type safety (since you can't just implicitly convert them to/from <code>int</code>).  It also lets you define fields and methods for additional functionality (e.g., custom string formatting and parsing).</p>
<p>Of course, you're not constrained to what's provided by your language's <code>enum</code> <em>keyword</em>.  It's possible to implement a C++ class that behaves like a Java enum, or a Java class that just defines a bunch of <code>public static final int</code> constants like a C(++) enum.</p>
<p>To recap,</p>
<ul>
<li>Java-style (class-based) = for richer functionality, type safety, and object-oriented design.</li>
<li>C(++) style (integer-based) = for low-level or performance-critical code, or interop with legacy C code.</li>
</ul>

CC BY-SA 4.0
2023-07-26T16:13:37.630Z
2023-07-28T12:22:03.067Z
2023-07-28T12:22:03.067Z
dan04
CC BY-SA 4.0
2023-07-26T17:09:16.750Z
Since Java enums are final, a large part of their functionality could be desugared into free functions and global variables instead. They could be boxed upon being converted to Object, if your language requires it
Criticize SE actions means ban
CC BY-SA 4.0
2023-07-27T04:58:49.137Z
It's worth noting that "since you can't just implicitly convert them to/from `int`" doesn't really depend on whether the enums are classes or just ints under the hood. The compiler can still refuse to let you cast implicitly, or even do the reverse and allow implicitly casting an `int` to an enum class
rydwolf
CC BY-SA 4.0
2023-07-27T05:04:14.803Z
Mind you, if we're talking language design rather than the specific features of C++ and Java, there's no reason that "it's just an int under the hood" style enums couldn't have type safety; C++ **chose** to make them implicitly convertable with integers. Likewise Java could have allowed class methods for enums *syntactically* while actually representing them as primitives and static functions. These are not inherent consequences of making enums represented as primitive ints or not, they are specific choices the language designers made (even if only to make things easier for implementers).
Ben
CC BY-SA 4.0
2023-07-27T13:16:09.077Z
I am not certain if you could get the same effect in Java as in C++. Not without completely doing away type safety and use simple ints as you suggested. Even plain enums has some type checking. You could definitely create Java style enums in C++.
Cem Kalyoncu
CC BY-SA 4.0
2023-07-27T20:09:02.610Z
If enumerations use compiler-assigned integer constants, a system could easily construct a singleton object for each value, and have an array of object references which can convert from an integer to an object every time boxing would be required, with no need to create a new object on every conversion.
supercat
CC BY-SA 4.0
2023-07-28T03:10:24.687Z
The example 2nd sentence of your 2nd paragraph is incorrect; enum class have no implicit conversion.  That isn't a great sign.  You also neglect to mention operator overloading and friend functions for C++ enums.  I suspect you don't understand `enum class`?
Yakk - Adam Nevraumont
<p>In C++ you can have a <em>plain enum</em> or an <em>enum class</em>, and the <em>enum class</em> is similar in some way to Java enums. So <em>plain enum</em> are more likely the one you are describing here when you say C++ enum.</p>
<p>In that case, enums are indeed aliases for integer constants: they convert automatically to the underlying type, even you don't want to, from a static typing point of view there is little difference. There can be values that belong the an enum type even if there is no enum with that value: if you define three values A, B and C (resp. bound to 0, 1 and 2), then <code>A|B|C</code> is a bitwise-or value equal to 3, which takes 2 bits and fits the underlying type of the enum, however this is not a proper enum value by itself.</p>
<p>A Java-type enum object can list all its values at runtime. The set of values is restricted to only the values that are defined by the enum, you cannot use an enum and an int interchangeably, you have to call the associated methods to convert from and to integers, from and to strings, etc.</p>
<p>I think there is little added-value for plain enums compared to, e.g. constants (or even preprocessor variables). A group of constants declarations is almost equivalent: the notation is shorter with plain enums, and there is an additional relationship between constants that is expressed by the construct. Only enum classes introduce a scope, for example (nb. compared to Java enums, enum classes in C++ don't have reflection).</p>
<p>Java-style enums are the standard now I think for any high-level language, when it is acceptable to have a little bit of runtime features that help the programmer. Writing low-level, resource contrained code is maybe the only case where I see a benefit in using plain enums.</p>

CC BY-SA 4.0
2023-07-26T15:39:31.367Z
2023-07-27T12:59:41.940Z
2023-07-27T12:59:41.940Z
coredump
CC BY-SA 4.0
2023-07-27T06:13:00.870Z
Plain enums have the benefit that they can be contained within a scope, making them more useful than preprocessor directives because they aren't forced to pollute the global namespace.  This allows them to be treated similarly to more proper objects by placing them inside a `struct`, though at that point you're essentially just reinventing Java-style enums.  (That said, it's also worth pointing out that as truly constant values, enum-in-struct was often used to provide `constexpr`-like functionality before C++11, for things like `std::string::npos` or template metaprogramming.)
Justin Time - Reinstate Monica
CC BY-SA 4.0
2023-07-27T07:22:08.693Z
but plain enums are unscoped?
coredump
CC BY-SA 4.0
2023-07-27T12:18:08.380Z
@coredump: Not quite, the enumerators of plain enums are in the _enclosing_ scope, so it's still better than macros which are in the global scope -- well, in C++ there _are_ enclosing scopes (namespaces, class/struct); in C there's only the global scope where enums can be declared, so there they lose value indeed.
Matthieu M.
CC BY-SA 4.0
2023-07-27T12:35:56.657Z
@MatthieuM. I edited the answer to focus on constants, I agree that preprocessor macros are just not equivalent (their only advantage is they can be stringified).
coredump
CC BY-SA 4.0
2023-07-27T12:44:50.573Z
@coredump: There actually is an advantage to using an `enum` for a group of constants => lints. C and C++ compilers have warning if you forget to handle an enumerator in a `switch`, and no equivalent for constants. There are also hacks to enumerate the enumerators of an `enum` in C++ (magic meta-template wizardry), for pseudo-reflection.
Matthieu M.
CC BY-SA 4.0
2023-07-27T12:54:53.763Z
Tangentially, I'm not sure your `ONE|TWO|THREE` example is the best possible choice: if you assign the obvious numeric values to those enum constants and bitwise OR them, then it just happens that `(1 | 2 | 3) == 3`.
Ilmari Karonen
CC BY-SA 4.0
2023-07-27T12:59:57.197Z
@IlmariKaronen I tried to make the example less ambiguous
coredump
CC BY-SA 4.0
2023-07-27T13:46:22.217Z
In C++, even non-class enums, when named, form a "real" type. You cannot assign integers to them. Incidentally, that would also cause your `enum E { e1=1; e2=2 }; E e = e1|e2;` to fail because the right hand side is an int. You'd have to say `E e = (E)(e1|e2);`. This is particularly valuable for type-safe interfaces: If you have another `enum EE { ee1 = 1; };` and a `void f(E e);` you cannot call  `EE ee = ee1; f(ee);`!
Peter - Reinstate Monica
CC BY-SA 4.0
2023-07-27T13:57:22.943Z
This is particularly valuable when you have functions with various integers and booleans like "void log(bool doInsert, bool toStdout,, bool doSuppress, int logLevel);` If you call `log(false, true, false, 0);` -- or even `log(false, true, false, false);`! -- nobody would know what you did without consulting the documentation. Compare that with appropriate enum definitions, resulting in a signature `void log(Insert_E doInsert, Stream_E stdoutOrStderr, Suppress_E doSupress, Loglevel_E logLevel);` and a call `log(DONT_INSERT, TO_STDOUT, DONT_SUPPRESS, LOG_MINIMUM);`.
Peter - Reinstate Monica
CC BY-SA 4.0
2023-07-27T15:30:52.137Z
There is one major benefit to enums in C and C++ over preprocessor directives and that is how enum tags are available to a debugger where preprocessor labels are lost. Enums can also be more compact compared with regular constant literals.
SoronelHaetir
CC BY-SA 4.0
2023-07-28T04:28:53.960Z
@Peter-ReinstateMonica With `E e = e1|e2;` you can overload `operator|` to return `E` for bitfield enums, getting rid of `(E)` cast.
Yakk - Adam Nevraumont
CC BY-SA 4.0
2023-07-28T08:34:09.623Z
@Yakk-AdamNevraumont Yes of course. The question is whether you want to do that because, as the OP demonstrated, you can generate values outside the range of named enum members.
Peter - Reinstate Monica
CC BY-SA 4.0
2023-07-29T18:18:21.023Z
You might or might not, @Peter-ReinstateMonica, depending on the context.  It's important to note that C++ allows enums to specify their underlying type ("scoped enums"), and defines all unscoped enums to have an underlying type large enough to hold any value within the smallest bitfield that can hold all enumerators, even if that value's not a named enumerator (e.g., `enum E { ONE = 1, TWO = 2, FOUR = 4 };` can hold any value representable by three bits, whether named enumerator or not, and thus has a range of `0..7`, because `FOUR` requires three bits).
Justin Time - Reinstate Monica
CC BY-SA 4.0
2023-07-29T18:26:33.427Z
Notably, @Peter-ReinstateMonica, the standard library does exactly this for [`std::launch`](https://en.cppreference.com/w/cpp/thread/launch), & is expected to be usable in this manner by [`std::async()`](https://en.cppreference.com/w/cpp/thread/async). `launch` defines a minimum of 2 enumerators, `async` and `deferred`, but the 1st version of `std::async` operates as if called with a `std::launch` value of `async | deferred`, which is _not_ formally defined as an enumerator; it's thus legal to pass `std::launch::async | std::launch::deferred` when calling the second version of `std::async()`.
Justin Time - Reinstate Monica
<p>When programming in C++ I sometimes miss the <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html" rel="nofollow noreferrer">additional methods</a> that come automatically with Java enums, especially an easy way to converted into string representation when logging, but also for parsing, obtaining next or previous value in the order and the like. In C++, you need to write your own free-standing functions to replace them. Free-standing functions are then quite difficult to find by another programmer who is not aware of them.</p>

CC BY-SA 4.0
2023-07-28T16:58:04.343Z
2023-07-28T16:58:04.343Z
Audrius Meškauskas
<p>For a complete comparison, we should add a 3rd (and 4th?) type of <code>enum</code>: Sum Types, as in Haskell or Rust.</p>
<h3>Scope</h3>
<p>C and C++ plain <code>enum</code> are unscoped. That is, their enumerators are part of the <em>enclosing</em> scope of the declaration<sup>1</sup>. This is largely seen as undesirable.</p>
<p>A contrario, Java, Haskell, and Rust's &quot;enumerators&quot; are scoped.</p>
<p><sup>1</sup> <em>In the early days of C, struct data members were also unscoped. This is why <code>struct tm</code> data members are all prefixed with <code>tm_</code>. struct data members were changed to be scoped, but enums were not.</em></p>
<h3>Full vs Partial</h3>
<p>C and C++ <code>enum</code> (plain or <code>class</code>) are partial, they are not guaranteed to hold a value matching an enumerator, and may instead hold any value achievable by bitwise ORing enumerators or, in the case of C++, any value which may fit in the specified underlying type, if any.</p>
<p>Java, Haskell, and Rust fully define the valid enumerators, and no other value is supported.</p>
<p><strong>Advantage C/C++</strong></p>
<ul>
<li><code>enum</code> can be used as a set of flags.</li>
</ul>
<p><strong>Advantage Java/Haskell/Rust</strong></p>
<ul>
<li>Most <code>enum</code> are not meant to be used as set of flags, so not having to worry about an exotic unnamed state is generally beneficial.</li>
</ul>
<p><strong>Advantage Rust</strong></p>
<ul>
<li>Niche optimizations mean that <code>Option&lt;E&gt;</code> where <code>E</code> is an enum, has the same size as <code>E</code>.</li>
</ul>
<h3>Overlap</h3>
<p>C and C++ <code>enum</code> may have multiple &quot;equal&quot; enumerators, that are indistinguishable from one another.</p>
<p>Java, Haskell, and Rust cannot have indistinguishable enumerators.</p>
<h3>Constant</h3>
<p>C and C++ <code>enum</code> are integers in disguise, their integer value can be specified and they can always be converted down to their integer representation. Similarly, in-range integers can be converted to <code>enum</code>.</p>
<p>Rust <code>enum</code> with no payloads can have a specified underlying integer representation (<code>#[repr(u8)]</code> is common) and specified integer values, in which case they can be converted to this representation (<code>e as u8</code>). There is no automatic conversion back from integer, as not all values may be valid enum values, but a user-written conversion function can be optimized down to the equivalent cast.</p>
<p>Java <code>enum</code> can be converted to an <code>int</code> using the <code>ordinal</code> method, the integer value is the index of the enumerator in the declaration.</p>
<p><strong>Advantage C/C++/Rust</strong></p>
<ul>
<li><code>enum</code> can be used to enumerate a fixed set of related integral constants, at no run-time cost.</li>
</ul>
<h3>Payload</h3>
<p>Java <code>enum</code> can have a state, though all enumerators must have the same set of fields.</p>
<p>Haskell and Rust enums are full sum types which can have a different set of fields per enumerator.</p>
<p><strong>Advantage Java</strong></p>
<ul>
<li>Per-enumerator state is easier to visual than a set of method each mapping an integer value to a specific state.</li>
</ul>
<p><strong>Advantage Haskell/Rust</strong></p>
<ul>
<li>Full blown sum types are a delight to program with, allowing expressing clearly which set of fields are relevant to a particular situation. The <code>Maybe</code> (Haskell) and <code>Option</code> (Rust) types completely eliminate the Billion Dollars mistake that is null, for example.</li>
</ul>
<h3>Methods</h3>
<p>C and C++ <code>enum</code> do not support methods.</p>
<p>Java, Haskell, and Rust enums are first-class user-defined types of the language, and support everything user-defined types do: associated constants, inherent methods, inheritance (Java) or typeclass/trait (Haskell/Rust) implementations, etc...</p>
<h3>Summary</h3>
<p>First, a classification by versatility:</p>
<ol>
<li><strong>Rust</strong> has the most versatile enums. They are first-class citizens of the language, while being able to boil down to an efficient integral representation.</li>
<li><strong>Haskell</strong> has the second most versatile enums. They are first-class citizens of the language, and sum types are just awesome programming tools.</li>
<li><strong>Java</strong> has the third most versatile enums. They are first-class citizens of the language, but are uniform.</li>
<li><strong>C and C++</strong> have the least versatile enums. They are second-class citizens of the language, and may hold unnamed values. They have very efficient integral representation, though.</li>
</ol>
<p>Getting down to the details, the one task that C and C++ enums can fulfill better than others is the role of set of flags <strong>if</strong> the enumerators are carefully defined. Java, Haskell, and Rust require user-written code to efficiently encode enum sets of integers, with Rust (at least) being able to optimize that code down to same assembly as C or C++.</p>
<p>Otherwise, first-class citizens <code>enum</code> are always preferable, and sum-types even more preferable.</p>

CC BY-SA 4.0
2023-07-27T13:28:00.613Z
2023-07-27T15:26:31.163Z
2023-07-27T15:26:31.163Z
Matthieu M.
CC BY-SA 4.0
2023-07-27T13:32:59.107Z
Swift has type-safe bitwise flags using `OptionSet`: https://langdev.stackexchange.com/a/1671/15 So that missing functionality of an `enum` isn't really felt.
Bbrk24
CC BY-SA 4.0
2023-07-27T14:34:25.127Z
@Bbrk24: I'm... not enthused, to be honest. I much prefer a bitset wrapper taking an arbitrary integral-like enum, since this way I can use the enum `E` by itself, when needed, and have my `EnumSet<E>` and `EnumMap<E, V>`.
Matthieu M.
CC BY-SA 4.0
2023-07-27T14:38:42.217Z
Really, this is beneficial because of Swift's base type inference rules. Instead of `edges(EDGE_LEFT | EDGE_TOP)` or `edges(edge::left | edge::top)` as in C++, Swift allows you to say `edges([.left, .top])`. There's no namespace pollution nor loss of type safety, yet it's briefer. Plus, you don't have to worry about whether it takes a `Set<Edge>` or an OptionSet type: the API is the same.
Bbrk24
CC BY-SA 4.0
2023-07-28T03:52:57.180Z
`std::variant` in C++ is an interesting "enum".  I sometimes do `std::variant<std::integral_constant<...>...>`  even.
Yakk - Adam Nevraumont
CC BY-SA 4.0
2023-07-28T06:49:14.533Z
@Yakk-AdamNevraumont: It's not part of the language... and its ergonomics suffer from that. The difference between `std::visit`  and `match` (Rust) is just night and day :(
Matthieu M.
CC BY-SA 4.0
2023-07-28T14:13:16.113Z
> Niche optimizations mean that Option<E> where E is an enum, has the same size as E.

Is this always true? What happens if you create an enum with 256 specified values, backed by a u8? There's no way to represent the absence anymore.
Kafein
CC BY-SA 4.0
2023-07-28T14:18:14.267Z
@Kafein: Well, it's true _if there's a niche_, so indeed if you have a enum with exactly 256 discriminants in a u8, there's no room. On the other hand, it does stack, so that `Option<Option<Option<Option<bool>>>>` is still a single byte (since a bool has only two valid states, you can stack 254 Options).
Matthieu M.
CC BY-SA 4.0
2023-07-31T17:49:34.650Z
Though, IMHO, to compare _enumerated types_ and _sum types_ as if the same is a tad bit unfair...
Pablo H
CC BY-SA 4.0
2023-08-01T09:42:51.570Z
@PabloH: Is it? In languages with sum types, there's no _distinct_ enumerated types: enumerated types are just seen as a special case of sum types with no payload.
Matthieu M.
CC BY-SA 4.0
2023-11-09T20:33:53.567Z
One observation... Java-style enums can be natively converted to an integer using their index within the enum... but because they're objects, it's also very easy to map them to arbitrary values, something we use quite extensively for database mappings where neither the enum name nor index is a suitable persistent value.
Simon Geard
CC BY-SA 4.0
2023-11-10T08:00:32.950Z
@SimonGeard: Although it only works (cheaply) in one direction. In C or C++ you can just reinterpret an integer as an enum, and in Rust you can do so (unsafely) as well. In Java, you'd need some look-up function -- that's what the lack of language support costs you.
Matthieu M.
CC BY-SA 4.0
2023-11-12T21:43:40.110Z
@MatthieuM. True, though if it's a common pattern (as it is for us), it's easy enough to bury that lookup function in framework code and convention.
Simon Geard
CC BY-SA 4.0
2023-11-13T08:24:08.600Z
@SimonGeard: Oh I'm not saying it can't be done, I'm just (very) performance minded... as you'd expect from a C/C++/Rust afficionado I guess.
Matthieu M.
# When would a Java style enum be better than a C++ style enum, and vice versa?
Posted by: username_0 on 2023-07-26
In Java, enum values behave like objects ([since they are basically syntactic sugar for objects](https://softwareengineering.stackexchange.com/questions/301542/understanding-enums-in-java)) and they can have their own class methods. In C++, however, enums are essentially an alias for an integer constant.

What are some possible situations where a Java type enum would be better/make more sense to be used and when would a C++ enum make more sense in a language?
**Tags:** c++ java enumerations
> **Comments:**
> **username_1**: There's a third kind of enum: sum types, as in Swift and Rust.  
> **username_2**: Also, Typescript's enums can be string constants, not just integers.  
> **username_3**: ... and then there's C#, which provides a C++-style enums, but allows to use extension methods on them. TBH you can even use extension methods on "primitive" types in C#, and that's one of the reasons I changed my mind about C# after 3.0  
---
## 4 answers
### Answer by username_13 on 2023-07-27. Score: 21
For a complete comparison, we should add a 3rd (and 4th?) type of `enum`: Sum Types, as in Haskell or Rust.

### Scope

C and C++ plain `enum` are unscoped. That is, their enumerators are part of the *enclosing* scope of the declaration1. This is largely seen as undesirable.

A contrario, Java, Haskell, and Rust's "enumerators" are scoped.

1 *In the early days of C, struct data members were also unscoped. This is why `struct tm` data members are all prefixed with `tm_`. struct data members were changed to be scoped, but enums were not.*

### Full vs Partial

C and C++ `enum` (plain or `class`) are partial, they are not guaranteed to hold a value matching an enumerator, and may instead hold any value achievable by bitwise ORing enumerators or, in the case of C++, any value which may fit in the specified underlying type, if any.

Java, Haskell, and Rust fully define the valid enumerators, and no other value is supported.

**Advantage C/C++**

* `enum` can be used as a set of flags.

**Advantage Java/Haskell/Rust**

* Most `enum` are not meant to be used as set of flags, so not having to worry about an exotic unnamed state is generally beneficial.

**Advantage Rust**

* Niche optimizations mean that `Option` where `E` is an enum, has the same size as `E`.

### Overlap

C and C++ `enum` may have multiple "equal" enumerators, that are indistinguishable from one another.

Java, Haskell, and Rust cannot have indistinguishable enumerators.

### Constant

C and C++ `enum` are integers in disguise, their integer value can be specified and they can always be converted down to their integer representation. Similarly, in-range integers can be converted to `enum`.

Rust `enum` with no payloads can have a specified underlying integer representation (`#[repr(u8)]` is common) and specified integer values, in which case they can be converted to this representation (`e as u8`). There is no automatic conversion back from integer, as not all values may be valid enum values, but a user-written conversion function can be optimized down to the equivalent cast.

Java `enum` can be converted to an `int` using the `ordinal` method, the integer value is the index of the enumerator in the declaration.

**Advantage C/C++/Rust**

* `enum` can be used to enumerate a fixed set of related integral constants, at no run-time cost.

### Payload

Java `enum` can have a state, though all enumerators must have the same set of fields.

Haskell and Rust enums are full sum types which can have a different set of fields per enumerator.

**Advantage Java**

* Per-enumerator state is easier to visual than a set of method each mapping an integer value to a specific state.

**Advantage Haskell/Rust**

* Full blown sum types are a delight to program with, allowing expressing clearly which set of fields are relevant to a particular situation. The `Maybe` (Haskell) and `Option` (Rust) types completely eliminate the Billion Dollars mistake that is null, for example.

### Methods

C and C++ `enum` do not support methods.

Java, Haskell, and Rust enums are first-class user-defined types of the language, and support everything user-defined types do: associated constants, inherent methods, inheritance (Java) or typeclass/trait (Haskell/Rust) implementations, etc...

### Summary

First, a classification by versatility:

1. **Rust** has the most versatile enums. They are first-class citizens of the language, while being able to boil down to an efficient integral representation.
2. **Haskell** has the second most versatile enums. They are first-class citizens of the language, and sum types are just awesome programming tools.
3. **Java** has the third most versatile enums. They are first-class citizens of the language, but are uniform.
4. **C and C++** have the least versatile enums. They are second-class citizens of the language, and may hold unnamed values. They have very efficient integral representation, though.

Getting down to the details, the one task that C and C++ enums can fulfill better than others is the role of set of flags **if** the enumerators are carefully defined. Java, Haskell, and Rust require user-written code to efficiently encode enum sets of integers, with Rust (at least) being able to optimize that code down to same assembly as C or C++.

Otherwise, first-class citizens `enum` are always preferable, and sum-types even more preferable.
> **Comments:**
> **username_1** (2023-07-27): Swift has type-safe bitwise flags using `OptionSet`: https://langdev.stackexchange.com/a/1671/15 So that missing functionality of an `enum` isn't really felt.  
> **username_13** (2023-07-27): @Bbrk24: I'm... not enthused, to be honest. I much prefer a bitset wrapper taking an arbitrary integral-like enum, since this way I can use the enum `E` by itself, when needed, and have my `EnumSet<E>` and `EnumMap<E, V>`.  
> **username_1** (2023-07-27): Really, this is beneficial because of Swift's base type inference rules. Instead of `edges(EDGE_LEFT | EDGE_TOP)` or `edges(edge::left | edge::top)` as in C++, Swift allows you to say `edges([.left, .top])`. There's no namespace pollution nor loss of type safety, yet it's briefer. Plus, you don't have to worry about whether it takes a `Set<Edge>` or an OptionSet type: the API is the same.  
> **username_10** (2023-07-28): `std::variant` in C++ is an interesting "enum".  I sometimes do `std::variant<std::integral_constant<...>...>`  even.  
> **username_13** (2023-07-28): @Yakk-AdamNevraumont: It's not part of the language... and its ergonomics suffer from that. The difference between `std::visit`  and `match` (Rust) is just night and day :(  
> **username_18** (2023-07-28): > Niche optimizations mean that Option<E> where E is an enum, has the same size as E.

Is this always true? What happens if you create an enum with 256 specified values, backed by a u8? There's no way to represent the absence anymore.  
> **username_13** (2023-07-28): @Kafein: Well, it's true _if there's a niche_, so indeed if you have a enum with exactly 256 discriminants in a u8, there's no room. On the other hand, it does stack, so that `Option<Option<Option<Option<bool>>>>` is still a single byte (since a bool has only two valid states, you can stack 254 Options).  
> **username_19** (2023-07-31): Though, IMHO, to compare _enumerated types_ and _sum types_ as if the same is a tad bit unfair...  
> **username_13** (2023-08-01): @PabloH: Is it? In languages with sum types, there's no _distinct_ enumerated types: enumerated types are just seen as a special case of sum types with no payload.  
> **username_20** (2023-11-09): One observation... Java-style enums can be natively converted to an integer using their index within the enum... but because they're objects, it's also very easy to map them to arbitrary values, something we use quite extensively for database mappings where neither the enum name nor index is a suitable persistent value.  
> **username_13** (2023-11-10): @SimonGeard: Although it only works (cheaply) in one direction. In C or C++ you can just reinterpret an integer as an enum, and in Rust you can do so (unsafely) as well. In Java, you'd need some look-up function -- that's what the lack of language support costs you.  
> **username_20** (2023-11-12): @MatthieuM. True, though if it's a common pattern (as it is for us), it's easy enough to bury that lookup function in framework code and convention.  
> **username_13** (2023-11-13): @SimonGeard: Oh I'm not saying it can't be done, I'm just (very) performance minded... as you'd expect from a C/C++/Rust afficionado I guess.  
---
### Answer by username_11 on 2023-07-26. Score: 7
In C++ you can have a *plain enum* or an *enum class*, and the *enum class* is similar in some way to Java enums. So *plain enum* are more likely the one you are describing here when you say C++ enum.

In that case, enums are indeed aliases for integer constants: they convert automatically to the underlying type, even you don't want to, from a static typing point of view there is little difference. There can be values that belong the an enum type even if there is no enum with that value: if you define three values A, B and C (resp. bound to 0, 1 and 2), then `A|B|C` is a bitwise-or value equal to 3, which takes 2 bits and fits the underlying type of the enum, however this is not a proper enum value by itself.

A Java-type enum object can list all its values at runtime. The set of values is restricted to only the values that are defined by the enum, you cannot use an enum and an int interchangeably, you have to call the associated methods to convert from and to integers, from and to strings, etc.

I think there is little added-value for plain enums compared to, e.g. constants (or even preprocessor variables). A group of constants declarations is almost equivalent: the notation is shorter with plain enums, and there is an additional relationship between constants that is expressed by the construct. Only enum classes introduce a scope, for example (nb. compared to Java enums, enum classes in C++ don't have reflection).

Java-style enums are the standard now I think for any high-level language, when it is acceptable to have a little bit of runtime features that help the programmer. Writing low-level, resource contrained code is maybe the only case where I see a benefit in using plain enums.
> **Comments:**
> **username_12** (2023-07-27): Plain enums have the benefit that they can be contained within a scope, making them more useful than preprocessor directives because they aren't forced to pollute the global namespace.  This allows them to be treated similarly to more proper objects by placing them inside a `struct`, though at that point you're essentially just reinventing Java-style enums.  (That said, it's also worth pointing out that as truly constant values, enum-in-struct was often used to provide `constexpr`-like functionality before C++11, for things like `std::string::npos` or template metaprogramming.)  
> **username_11** (2023-07-27): but plain enums are unscoped?  
> **username_13** (2023-07-27): @coredump: Not quite, the enumerators of plain enums are in the _enclosing_ scope, so it's still better than macros which are in the global scope -- well, in C++ there _are_ enclosing scopes (namespaces, class/struct); in C there's only the global scope where enums can be declared, so there they lose value indeed.  
> **username_11** (2023-07-27): @MatthieuM. I edited the answer to focus on constants, I agree that preprocessor macros are just not equivalent (their only advantage is they can be stringified).  
> **username_13** (2023-07-27): @coredump: There actually is an advantage to using an `enum` for a group of constants => lints. C and C++ compilers have warning if you forget to handle an enumerator in a `switch`, and no equivalent for constants. There are also hacks to enumerate the enumerators of an `enum` in C++ (magic meta-template wizardry), for pseudo-reflection.  
> **username_14** (2023-07-27): Tangentially, I'm not sure your `ONE|TWO|THREE` example is the best possible choice: if you assign the obvious numeric values to those enum constants and bitwise OR them, then it just happens that `(1 | 2 | 3) == 3`.  
> **username_11** (2023-07-27): @IlmariKaronen I tried to make the example less ambiguous  
> **username_15** (2023-07-27): In C++, even non-class enums, when named, form a "real" type. You cannot assign integers to them. Incidentally, that would also cause your `enum E { e1=1; e2=2 }; E e = e1|e2;` to fail because the right hand side is an int. You'd have to say `E e = (E)(e1|e2);`. This is particularly valuable for type-safe interfaces: If you have another `enum EE { ee1 = 1; };` and a `void f(E e);` you cannot call  `EE ee = ee1; f(ee);`!  
> **username_15** (2023-07-27): This is particularly valuable when you have functions with various integers and booleans like "void log(bool doInsert, bool toStdout,, bool doSuppress, int logLevel);` If you call `log(false, true, false, 0);` -- or even `log(false, true, false, false);`! -- nobody would know what you did without consulting the documentation. Compare that with appropriate enum definitions, resulting in a signature `void log(Insert_E doInsert, Stream_E stdoutOrStderr, Suppress_E doSupress, Loglevel_E logLevel);` and a call `log(DONT_INSERT, TO_STDOUT, DONT_SUPPRESS, LOG_MINIMUM);`.  
> **username_16** (2023-07-27): There is one major benefit to enums in C and C++ over preprocessor directives and that is how enum tags are available to a debugger where preprocessor labels are lost. Enums can also be more compact compared with regular constant literals.  
> **username_10** (2023-07-28): @Peter-ReinstateMonica With `E e = e1|e2;` you can overload `operator|` to return `E` for bitfield enums, getting rid of `(E)` cast.  
> **username_15** (2023-07-28): @Yakk-AdamNevraumont Yes of course. The question is whether you want to do that because, as the OP demonstrated, you can generate values outside the range of named enum members.  
> **username_12** (2023-07-29): You might or might not, @Peter-ReinstateMonica, depending on the context.  It's important to note that C++ allows enums to specify their underlying type ("scoped enums"), and defines all unscoped enums to have an underlying type large enough to hold any value within the smallest bitfield that can hold all enumerators, even if that value's not a named enumerator (e.g., `enum E { ONE = 1, TWO = 2, FOUR = 4 };` can hold any value representable by three bits, whether named enumerator or not, and thus has a range of `0..7`, because `FOUR` requires three bits).  
> **username_12** (2023-07-29): Notably, @Peter-ReinstateMonica, the standard library does exactly this for [`std::launch`](https://en.cppreference.com/w/cpp/thread/launch), & is expected to be usable in this manner by [`std::async()`](https://en.cppreference.com/w/cpp/thread/async). `launch` defines a minimum of 2 enumerators, `async` and `deferred`, but the 1st version of `std::async` operates as if called with a `std::launch` value of `async | deferred`, which is _not_ formally defined as an enumerator; it's thus legal to pass `std::launch::async | std::launch::deferred` when calling the second version of `std::async()`.  
---
### Answer by username_4 on 2023-07-26. Score: 6
C++ enums are essentially just `int` constants. This makes them efficient to implement, and usable for low-level or performance-critical programs.

OTOH, Java-style enums have full `class` functionality. They provides better type safety (since you can't just implicitly convert them to/from `int`). It also lets you define fields and methods for additional functionality (e.g., custom string formatting and parsing).

Of course, you're not constrained to what's provided by your language's `enum` *keyword*. It's possible to implement a C++ class that behaves like a Java enum, or a Java class that just defines a bunch of `public static final int` constants like a C(++) enum.

To recap,

* Java-style (class-based) = for richer functionality, type safety, and object-oriented design.
* C(++) style (integer-based) = for low-level or performance-critical code, or interop with legacy C code.
> **Comments:**
> **username_5** (2023-07-26): Since Java enums are final, a large part of their functionality could be desugared into free functions and global variables instead. They could be boxed upon being converted to Object, if your language requires it  
> **username_6** (2023-07-27): It's worth noting that "since you can't just implicitly convert them to/from `int`" doesn't really depend on whether the enums are classes or just ints under the hood. The compiler can still refuse to let you cast implicitly, or even do the reverse and allow implicitly casting an `int` to an enum class  
> **username_7** (2023-07-27): Mind you, if we're talking language design rather than the specific features of C++ and Java, there's no reason that "it's just an int under the hood" style enums couldn't have type safety; C++ **chose** to make them implicitly convertable with integers. Likewise Java could have allowed class methods for enums *syntactically* while actually representing them as primitives and static functions. These are not inherent consequences of making enums represented as primitive ints or not, they are specific choices the language designers made (even if only to make things easier for implementers).  
> **username_8** (2023-07-27): I am not certain if you could get the same effect in Java as in C++. Not without completely doing away type safety and use simple ints as you suggested. Even plain enums has some type checking. You could definitely create Java style enums in C++.  
> **username_9** (2023-07-27): If enumerations use compiler-assigned integer constants, a system could easily construct a singleton object for each value, and have an array of object references which can convert from an integer to an object every time boxing would be required, with no need to create a new object on every conversion.  
> **username_10** (2023-07-28): The example 2nd sentence of your 2nd paragraph is incorrect; enum class have no implicit conversion.  That isn't a great sign.  You also neglect to mention operator overloading and friend functions for C++ enums.  I suspect you don't understand `enum class`?  
---
### Answer by username_17 on 2023-07-28. Score: 1
When programming in C++ I sometimes miss the [additional methods](https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html) that come automatically with Java enums, especially an easy way to converted into string representation when logging, but also for parsing, obtaining next or previous value in the order and the like. In C++, you need to write your own free-standing functions to replace them. Free-standing functions are then quite difficult to find by another programmer who is not aware of them.
---
