<p>I don't know the standard words for these, but:</p>
<ul>
<li>complex enum is like <code>enum { E1(t1: T1, t2: T2, ...), E2(...), ... }</code></li>
<li>simple enum is like <code>enum { E1(T1), E2(T2), ... }</code></li>
</ul>
<p>The difference is for the constructor, the simple one always contain a tag and a type, the complex one contains a tag and multiple name-type pairs.</p>
<p>In a language with struct, you can always simulate complex enum by simple enum + struct, and the simple version feels much orthogonal.</p>
<p>But most languages even toy ones prefer complex enum. Why?</p>
<hr />
<p>Example:</p>
<p>A complex enum:</p>
<pre><code>enum Ast { TypeDef(name: Str, body: Ast), Ident(str: Str) }
</code></pre>
<p>simple enum:</p>
<pre><code>enum Ast { TypeDef(TypeDef), Ident(Str) }
struct TypeDef { name: Str, body: Ast }
</code></pre>

<language-design><union-types>
Why do most languages prefer complex enum instead of simple enum?
CC BY-SA 4.0
2023-05-19T03:22:59.370Z
@Isaiah I am confused. The question sounds crystal clear to me. What in particular do you think is confusing? The OP has given examples already.
ice1000
CC BY-SA 4.0
2023-05-19T03:47:27.183Z
@Isaiah example added. I don't know any langauge actually used the simple enum one, except Mini-TT which is only a tutorial.
molikto
CC BY-SA 4.0
2023-05-19T04:02:52.510Z
Is this really true? What you call a "complex enum" is normally called an [algebraic data type](https://en.wikipedia.org/wiki/Algebraic_data_type), though it is called an "enum" in e.g. Rust. On the other hand, enums in most languages I know are simply enumerated lists of values, often represented by consecutive integers, with no further structure. The kind you call a "simple enum" looks like what I would call a "[sum type](https://en.wikipedia.org/wiki/Tagged_union)" or "tagged union", and I don't know of any languages that call this an enum.
kaya3
CC BY-SA 4.0
2023-05-19T04:07:53.360Z
@kaya3 I fear whatever terminology I use they might defined differently by other people. So I just came up with my own definition. For example what you calls sum type only have two constructors, but what I call "simple enum" can have multiple ones.
molikto
CC BY-SA 4.0
2023-05-19T04:13:10.587Z
I don't think "sum type" has the connotation of only two constituents, but "tagged union" certainly doesn't. I think your phrase "simple enum" is misleading because people would expect this to mean traditional enums, i.e. enumerated lists of values with no further structure. In any case it is better to use established terminology rather than invent your own.
kaya3
CC BY-SA 4.0
2023-05-19T04:39:45.920Z
Now you say it I realized it can be misleading, but again, I have defined what I means. I still want to avoid reusing any existing terminology as they are most of time define in a specific context. I don't know what terminology should I use
molikto
CC BY-SA 4.0
2024-01-29T16:20:49.027Z
@kaya3 Tyr uses the enum keyword for tagged unions as the tag is an enum. I don't think that the enum concept in this question reflects what a tagged union in Ada or Tyr is. Or any enum concept I know. Te me, it reads like a (flat?) sealed hierarchy of records.
feldentm
CC BY-SA 4.0
2024-01-29T16:20:59.240Z
So, if "most languages" is correct, @molikto, please add at least one example.
feldentm
<p>I feel mainly two reasons:</p>
<ol>
<li>Structs corresponding to a single enum variant needs a name, while they have only one canonical use case, so it might be desirable to make these structs anonymous, hence the inlined version.</li>
<li>If your language supports tuples, it's definitely going to be a common pattern for users to have <code>E1((T1, T2, ...))</code>, which, the ability to unwrap the parentheses would be syntactically convenient. This is no longer a case when the syntax of enum variant types are not using parentheses already, see comments.</li>
<li>You can implement the simple enums in the core language and implement an elaboration feature. This is good for both compiler and the users.</li>
<li>Enums were evolved from C enums where no fields are allowed, which is a special case of n-ary (complex) enums, but slightly more cumbersome with simple ones.</li>
</ol>

CC BY-SA 4.0
2023-05-19T03:20:52.747Z
2023-05-19T04:10:52.420Z
2023-05-19T04:10:52.420Z
ice1000
CC BY-SA 4.0
2023-05-19T03:25:27.633Z
for 1, say I have `enum Ast { TypeDef(name: ..., body:...) }`. I always found I will need to define a function on `TypeDef`.  So I ends up writting  `enum Ast { TypeDef(TypeDef) }` where `TypeDef` isn't inlined.
molikto
CC BY-SA 4.0
2023-05-19T03:26:32.473Z
for 2, is it a syntax thing? What if the syntax for tagging is `t1@T1`? Then the syntax will be less noisy
molikto
CC BY-SA 4.0
2023-05-19T03:31:47.603Z
I've edited my answer to address your questions.
ice1000
<p>One advantage of &quot;complex enums&quot; over &quot;simple enums&quot; combined with separately defined structs is that not having the structure be a type in it's own right can enable more efficient packing of the members.</p>
<p>A common constraint in programming languages is that the size of a type must be a multiple of it's alignment requirement. If you don't have that constraint then the definition of arrays gets rather messier.</p>
<p>If you have a &quot;complex enum&quot; as a single data type, and either you allow the compiler to reorder fields or you have the programmer order fields in the most efficient manner then you only pay the price for rounding up to the next multiple of the alignment requirement once. On the other hand if you nest a struct inside a &quot;simple enum&quot; you pay that penalty twice.</p>

CC BY-SA 4.0
2024-01-29T14:52:12.843Z
2024-01-29T14:52:12.843Z
Peter Green
# Why do most languages prefer complex enum instead of simple enum?
Posted by: username_0 on 2023-05-19
I don't know the standard words for these, but:

complex enum is like enum { E1(t1: T1, t2: T2, ...), E2(...), ... }
simple enum is like enum { E1(T1), E2(T2), ... }

The difference is for the constructor, the simple one always contain a tag and a type, the complex one contains a tag and multiple name-type pairs.
In a language with struct, you can always simulate complex enum by simple enum + struct, and the simple version feels much orthogonal.
But most languages even toy ones prefer complex enum. Why?

Example:
A complex enum:
enum Ast { TypeDef(name: Str, body: Ast), Ident(str: Str) }

simple enum:
enum Ast { TypeDef(TypeDef), Ident(Str) }
struct TypeDef { name: Str, body: Ast }
**Tags:** language-design union-types
> **Comments:**
> **username_1**: @Isaiah I am confused. The question sounds crystal clear to me. What in particular do you think is confusing? The OP has given examples already.  
> **username_0**: @Isaiah example added. I don't know any langauge actually used the simple enum one, except Mini-TT which is only a tutorial.  
> **username_2**: Is this really true? What you call a "complex enum" is normally called an [algebraic data type](https://en.wikipedia.org/wiki/Algebraic_data_type), though it is called an "enum" in e.g. Rust. On the other hand, enums in most languages I know are simply enumerated lists of values, often represented by consecutive integers, with no further structure. The kind you call a "simple enum" looks like what I would call a "[sum type](https://en.wikipedia.org/wiki/Tagged_union)" or "tagged union", and I don't know of any languages that call this an enum.  
> **username_0**: @kaya3 I fear whatever terminology I use they might defined differently by other people. So I just came up with my own definition. For example what you calls sum type only have two constructors, but what I call "simple enum" can have multiple ones.  
> **username_2**: I don't think "sum type" has the connotation of only two constituents, but "tagged union" certainly doesn't. I think your phrase "simple enum" is misleading because people would expect this to mean traditional enums, i.e. enumerated lists of values with no further structure. In any case it is better to use established terminology rather than invent your own.  
> **username_0**: Now you say it I realized it can be misleading, but again, I have defined what I means. I still want to avoid reusing any existing terminology as they are most of time define in a specific context. I don't know what terminology should I use  
> **username_3**: @kaya3 Tyr uses the enum keyword for tagged unions as the tag is an enum. I don't think that the enum concept in this question reflects what a tagged union in Ada or Tyr is. Or any enum concept I know. Te me, it reads like a (flat?) sealed hierarchy of records.  
> **username_3**: So, if "most languages" is correct, @molikto, please add at least one example.  
---
## 2 answers
### Answer by username_1 on 2023-05-19. Score: 5
I feel mainly two reasons:

1. Structs corresponding to a single enum variant needs a name, while they have only one canonical use case, so it might be desirable to make these structs anonymous, hence the inlined version.
2. If your language supports tuples, it's definitely going to be a common pattern for users to have `E1((T1, T2, ...))`, which, the ability to unwrap the parentheses would be syntactically convenient. This is no longer a case when the syntax of enum variant types are not using parentheses already, see comments.
3. You can implement the simple enums in the core language and implement an elaboration feature. This is good for both compiler and the users.
4. Enums were evolved from C enums where no fields are allowed, which is a special case of n-ary (complex) enums, but slightly more cumbersome with simple ones.
> **Comments:**
> **username_0** (2023-05-19): for 1, say I have `enum Ast { TypeDef(name: ..., body:...) }`. I always found I will need to define a function on `TypeDef`.  So I ends up writting  `enum Ast { TypeDef(TypeDef) }` where `TypeDef` isn't inlined.  
> **username_0** (2023-05-19): for 2, is it a syntax thing? What if the syntax for tagging is `t1@T1`? Then the syntax will be less noisy  
> **username_1** (2023-05-19): I've edited my answer to address your questions.  
---
### Answer by username_4 on 2024-01-29. Score: 3
One advantage of "complex enums" over "simple enums" combined with separately defined structs is that not having the structure be a type in it's own right can enable more efficient packing of the members.

A common constraint in programming languages is that the size of a type must be a multiple of it's alignment requirement. If you don't have that constraint then the definition of arrays gets rather messier.

If you have a "complex enum" as a single data type, and either you allow the compiler to reorder fields or you have the programmer order fields in the most efficient manner then you only pay the price for rounding up to the next multiple of the alignment requirement once. On the other hand if you nest a struct inside a "simple enum" you pay that penalty twice.
---
