<p>The '<a href="https://langdev.stackexchange.com/questions/1970/what-is-the-type-and-correct-name-of-a-member-of-an-enumeration">atoms</a>' of an enumeration are separate but consider the following different flavours</p>
<pre><code>enum colour
{
   red,
   green,
   blue
}

enum day
{
   monday
   tuesday
   wednesday
   thursday
   friday
   saturday
   sunday
}

enum displayOption
{
   choice1,
   choice2,
   choice3
}

enum flags
{
   carry = 1
   overflow = 2
   error = 4
   blah = 8
}

enum magicNumbers
{
   x = 1
   y = 3
   z = 10
   lastValue = 10
}
</code></pre>
<p>For the <code>day</code> type it makes sense to support increment and wraparound. That is to have <code>monday++ -&gt; tuesday</code> &amp;  <code>sunday++ -&gt; monday</code> because it (actually the tag) is really a modular integer in the range 0..6 in disguise.</p>
<p>Incrementing enums is also useful if they represent choices you can cycle through in a GUI (like displayOption).</p>
<p>Occasionally you come across some (like magicNumbers) where there are synonyms that have the same tag or possibly a sentinel value.</p>
<p>Although you may see:</p>
<pre><code>enum colour
{
   red,
   green,
   blue
}
</code></pre>
<p>In practice this can be generalised to</p>
<pre><code>enum colour
{
   red    = 0,
   green  = 1,
   blue   = 2
}
</code></pre>
<p>or 'better' yet to</p>
<pre><code>enum colour
{
  {red   , 0},
  {green , 1},
  {blue  , 2}
}
</code></pre>
<p>So an enum actually represents a mapping from a label to value  or a tag to an atom depending on your view.</p>
<p>If you allow non-numeric values you have a discriminated union.</p>
<p>In the case of sequential integer tags you can view incrementing as incrementing the tag.
You don't have to do it that way though. You could instead define a successor operation that jumps to the next mapping in the tuple.</p>
<p>Days of the week is an obvious case where the iteration should wrap around
but they may be other cases where values should saturate instead.</p>
<p>C++ gets around this issue by having an enum (which doesn't support arithmetic) implictly convert to an integer (which does). See for exmaple <a href="https://www.embedded.com/enumerations-as-counters/" rel="noreferrer">https://www.embedded.com/enumerations-as-counters/</a>
Converting back can be a problem if the resulting integer is not a valid tag for a atom.</p>
<p>We have several choices for both representation and implementation.</p>
<ul>
<li>enum = unordered set of atoms</li>
<li>enum = ordered set of atoms - convertible to an integer</li>
<li>enum = bidrectional map of atoms to values, where each may only appear once</li>
<li>enum = bidrectional map of atoms to values, with aliases</li>
</ul>
<p>Should we have different names for these slightly different concepts?</p>
<p>What are the pros and cons of different representations and allowing enumerations to be incremented or share values?</p>
<p>I have my own opinions on this but I value the wisdom of this group.
The naming issue is perhaps the harder to answer. There may be some insight from type theorists.</p>

<enumerations>
Kinds of enumeration and increment/decrement
CC BY-SA 4.0
2023-07-07T12:26:38.360Z
If the language doesn't have "++" for enums, it's easy enough to provide functions such as `following(day) { return (Day)((1+(int)day) % DAYS)) }` and a similar `previous(day`)`, or even a function that adds a given number of days. The point is to make using it easy and obvious.
Ray Butterworth
<h2>Trait + Macro</h2>
<p>It is not recommended to add multiple enumerations keywords or syntax, because it is very inflexible.</p>
<ul>
<li>First of all, it is relatively rare that there is an order between ids</li>
<li>Second, the nature of the traversal is determined by the requirements
<ul>
<li>Sometimes it is necessary to allow forward traversal, and sometimes it is necessary to prohibit reverse traversal.</li>
<li>For the missing id in the middle, sometimes an error needs to be reported, and sometimes it needs to be ignored.</li>
<li>For the case of id overflow, sometimes it is necessary to report an error, and sometimes it is necessary to take a modulus.</li>
</ul>
</li>
</ul>
<p>With such changing requirements, the best way is to provide a polymorphic mechanism to overload <code>++</code>, <code>+=</code> and other operators.</p>
<p>If in rust, do this:</p>
<pre class="lang-rust prettyprint-override"><code>#[repr(u32)]
enum Day {
    Sunday = 0,
    Monday = 1,
    Tuesday = 2,
    Wednesday = 3,
    Thursday = 4,
    Friday = 5,
    Saturday = 6,
}

impl Add&lt;u32&gt; for Day {
    type Output = Self;

    fn add(self, rhs: u32) -&gt; Self::Output {
        let mut day = self as u32;
        day += rhs;
        day %= 7;
        unsafe { std::mem::transmute(day) }
    }
}
</code></pre>
<p>Then add derive macros for some commonly used modes.</p>
<p>At this time, to rotate and ignore non-sequential ids can be written as:</p>
<pre class="lang-rust prettyprint-override"><code>#[derive(traverse)]
#[traverse(rotate, ignore)]
enum flags
{
   carry = 1
   overflow = 2
   error = 4
   blah = 8
}
</code></pre>
<p>You can also add <code>modulo</code> to require loop modulo on overflow.</p>
<p>More complex cases can also fall back to manually implementing the <code>+=</code> trait.</p>

CC BY-SA 4.0
2023-07-07T02:13:56.480Z
2023-07-07T02:13:56.480Z
Aster
<p>Swift handles some of these differently.</p>
<blockquote>
<p>unordered set of atoms</p>
</blockquote>
<p>A normal enum:</p>
<pre class="lang-swift prettyprint-override"><code>enum Color {
  case red, green, blue
}
</code></pre>
<blockquote>
<p>ordered set of atoms - convertible to an integer</p>
</blockquote>
<p>A <a href="https://developer.apple.com/documentation/swift/rawrepresentable" rel="nofollow noreferrer"><code>RawRepresentable</code></a> enum:</p>
<pre class="lang-swift prettyprint-override"><code>enum Day: Int {
  case sunday = 0,
    monday, tuesday, wednesday, thursday, friday, saturday
}
</code></pre>
<p>Conversion <em>from</em> an integer is failable -- it returns <code>Day?</code> rather than <code>Day</code> -- in case there's an invalid value. Numeric operations are not available implicitly, but you could provide them:</p>
<pre class="lang-swift prettyprint-override"><code>extension Day {
  static func += (lhs: inout Day, rhs: Int) {
    var newValue = (lhs.rawValue + rhs) % 7
    if newValue &lt; 0 { newValue += 7 }
    lhs = .init(rawValue: newValue)!
  }
}
</code></pre>
<blockquote>
<p>bidrectional map of atoms to values, where each may only appear once</p>
</blockquote>
<p>An <a href="https://developer.apple.com/documentation/swift/optionset-swift.protocol" rel="nofollow noreferrer"><code>OptionSet</code></a> struct:</p>
<pre class="lang-swift prettyprint-override"><code>struct Flags: OptionSet {
  var rawValue: Int

  static let carry = Flags(rawValue: 1 &lt;&lt; 0)
  static let overflow = Flags(rawValue: 1 &lt;&lt; 1)
  static let error = Flags(rawValue: 1 &lt;&lt; 2)
  static let blah = Flags(rawValue: 1 &lt;&lt; 3)
}
</code></pre>
<p>For a detailed example, see my answer here: <a href="https://langdev.stackexchange.com/a/1671/15">https://langdev.stackexchange.com/a/1671/15</a>.</p>
<blockquote>
<p>bidrectional map of atoms to values, with aliases</p>
</blockquote>
<p>It's not super clear to me what you mean by this, but as I understand it, this could be a <code>RawRepresentable</code> enum:</p>
<pre class="lang-swift prettyprint-override"><code>enum MagicNumbers: Int {
  case x = 1
  case y = 3
  case z = 10

  static let lastValue = z
}
</code></pre>
<p>Each <em>distinct</em> value is marked with <code>case</code>, and the aliases are marked <code>static let</code>.</p>

CC BY-SA 4.0
2023-07-07T01:15:00.073Z
2023-07-07T12:00:39.237Z
2023-07-07T12:00:39.237Z
Bbrk24
# Kinds of enumeration and increment/decrement
Posted by: username_0 on 2023-07-07
The 'atoms' of an enumeration are separate but consider the following different flavours
enum colour
{
   red,
   green,
   blue
}

enum day
{
   monday
   tuesday
   wednesday
   thursday
   friday
   saturday
   sunday
}

enum displayOption
{
   choice1,
   choice2,
   choice3
}

enum flags
{
   carry = 1
   overflow = 2
   error = 4
   blah = 8
}

enum magicNumbers
{
   x = 1
   y = 3
   z = 10
   lastValue = 10
}

For the day type it makes sense to support increment and wraparound. That is to have monday++ -> tuesday &  sunday++ -> monday because it (actually the tag) is really a modular integer in the range 0..6 in disguise.
Incrementing enums is also useful if they represent choices you can cycle through in a GUI (like displayOption).
Occasionally you come across some (like magicNumbers) where there are synonyms that have the same tag or possibly a sentinel value.
Although you may see:
enum colour
{
   red,
   green,
   blue
}

In practice this can be generalised to
enum colour
{
   red    = 0,
   green  = 1,
   blue   = 2
}

or 'better' yet to
enum colour
{
  {red   , 0},
  {green , 1},
  {blue  , 2}
}

So an enum actually represents a mapping from a label to value  or a tag to an atom depending on your view.
If you allow non-numeric values you have a discriminated union.
In the case of sequential integer tags you can view incrementing as incrementing the tag.
You don't have to do it that way though. You could instead define a successor operation that jumps to the next mapping in the tuple.
Days of the week is an obvious case where the iteration should wrap around
but they may be other cases where values should saturate instead.
C++ gets around this issue by having an enum (which doesn't support arithmetic) implictly convert to an integer (which does). See for exmaple https://www.embedded.com/enumerations-as-counters/
Converting back can be a problem if the resulting integer is not a valid tag for a atom.
We have several choices for both representation and implementation.

enum = unordered set of atoms
enum = ordered set of atoms - convertible to an integer
enum = bidrectional map of atoms to values, where each may only appear once
enum = bidrectional map of atoms to values, with aliases

Should we have different names for these slightly different concepts?
What are the pros and cons of different representations and allowing enumerations to be incremented or share values?
I have my own opinions on this but I value the wisdom of this group.
The naming issue is perhaps the harder to answer. There may be some insight from type theorists.
**Tags:** enumerations
> **Comments:**
> **username_1**: If the language doesn't have "++" for enums, it's easy enough to provide functions such as `following(day) { return (Day)((1+(int)day) % DAYS)) }` and a similar `previous(day`)`, or even a function that adds a given number of days. The point is to make using it easy and obvious.  
---
## 2 answers
### Answer by username_3 on 2023-07-07. Score: 4
Swift handles some of these differently.

unordered set of atoms

A normal enum:
enum Color {
  case red, green, blue
}


ordered set of atoms - convertible to an integer

A RawRepresentable enum:
enum Day: Int {
  case sunday = 0,
    monday, tuesday, wednesday, thursday, friday, saturday
}

Conversion from an integer is failable -- it returns Day? rather than Day -- in case there's an invalid value. Numeric operations are not available implicitly, but you could provide them:
extension Day {
  static func += (lhs: inout Day, rhs: Int) {
    var newValue = (lhs.rawValue + rhs) % 7
    if newValue < 0 { newValue += 7 }
    lhs = .init(rawValue: newValue)!
  }
}


bidrectional map of atoms to values, where each may only appear once

An OptionSet struct:
struct Flags: OptionSet {
  var rawValue: Int

  static let carry = Flags(rawValue: 1 << 0)
  static let overflow = Flags(rawValue: 1 << 1)
  static let error = Flags(rawValue: 1 << 2)
  static let blah = Flags(rawValue: 1 << 3)
}

For a detailed example, see my answer here: https://langdev.stackexchange.com/a/1671/15.

bidrectional map of atoms to values, with aliases

It's not super clear to me what you mean by this, but as I understand it, this could be a RawRepresentable enum:
enum MagicNumbers: Int {
  case x = 1
  case y = 3
  case z = 10

  static let lastValue = z
}

Each distinct value is marked with case, and the aliases are marked static let.
---
### Answer by username_2 on 2023-07-07. Score: 2
Trait + Macro
It is not recommended to add multiple enumerations keywords or syntax, because it is very inflexible.

First of all, it is relatively rare that there is an order between ids
Second, the nature of the traversal is determined by the requirements

Sometimes it is necessary to allow forward traversal, and sometimes it is necessary to prohibit reverse traversal.
For the missing id in the middle, sometimes an error needs to be reported, and sometimes it needs to be ignored.
For the case of id overflow, sometimes it is necessary to report an error, and sometimes it is necessary to take a modulus.



With such changing requirements, the best way is to provide a polymorphic mechanism to overload ++, += and other operators.
If in rust, do this:
#[repr(u32)]
enum Day {
    Sunday = 0,
    Monday = 1,
    Tuesday = 2,
    Wednesday = 3,
    Thursday = 4,
    Friday = 5,
    Saturday = 6,
}

impl Add for Day {
    type Output = Self;

    fn add(self, rhs: u32) -> Self::Output {
        let mut day = self as u32;
        day += rhs;
        day %= 7;
        unsafe { std::mem::transmute(day) }
    }
}

Then add derive macros for some commonly used modes.
At this time, to rotate and ignore non-sequential ids can be written as:
#[derive(traverse)]
#[traverse(rotate, ignore)]
enum flags
{
   carry = 1
   overflow = 2
   error = 4
   blah = 8
}

You can also add modulo to require loop modulo on overflow.
More complex cases can also fall back to manually implementing the += trait.
---
