Generic dynamic array of enums

So I want a dynamic array of a generic enum type. Something like this:

package enum_test

import "base:intrinsics"

foo :: struct ( $E : typeid ) where intrinsics.type_is_enum ( E ) {
    id: E
}

bar :: struct { into : []dynamic foo }

blarg :: enum { a, b }

point :: enum { zort, narf }

main :: proc() {
    bleh : bar
    append( &bleh.into, foo( blarg ) { blarg.a } )

    blue : bar
    append( &blue.into, foo( point ) { point.zort } )
}

The problem is that I want an enum inside a parapoly struct , then to put that struct inside a monomorphic struct. Enumerated arrays won’t work, they are an array with size = enum which is a different concept.

I understand that if enum types are solved at compile-time, then the fields in a struct need to know the size of the type, and enums can be an integer of any size. If I could use a generic enum type where I specify the integer type (int, u8, … ) this problem would be solved, and as far as I know there’s no such thing.

Having something like a generic enum type would be difficult since an enum is not a specific type, but a group of types. That’s why ‘enum’ is a keyword. Even if I didn’t want an array but a single ‘generic’ enum type without specifying the specific type of enum, there’s no generic enum.

Looking at the overview, I’d say that something like ‘enum integer’ (or integer enum) is an abstract type, though I feel the untyped types in the overview can only be constants, which is not what I want. An ‘enum integer’ would require moving the concept of enum from keyword to built-in type.

I ranted this much because I was trying to see if I am missing something.

The one way I have thought of to solve this is to store the enum value as an int, and the enum type in a type id. When I want to use the enum, I’d cast the int to the enum type during runtime. I’d prefer if it were solved during compilation.

A c-style enum would allow at least using the enum element identifiers as indexes, even if I losethe stricter typing. I could achieve something similar by making a bunch of constants, but then I lose the syntactic sugar of enums.

If anyone has any other ideas on how to solve this, let me know.

Ultimately, it’s up to you to somehow know which element is which type, so:

  • you could either store a typeid per element,
  • if you know which element is which type in some other way, you could do the type erasure way where all the enums have the same backing integer,
  • or perhaps if those dynamic arrays are all the same enum you could cast them (but it doesn’t sound like that).

It would help to know more about the actual use case, because I’m just throwing some general possibilities around.

So I thought about this a lot, and I think I’m just asking for the impossible. You would be able to covert to an abstract type at compilation time but no matter what it’s not possible to do this in this manner without runtime polymorphism.

I could have also done during compilation time if struct constants from parapoly expressions were a thing.

Welp, I found that there are compile-time constants in structs / unions, they just not mentioned as such :sweat_smile:

So after all I just need to get a proper mental model of Odin instead of ranting and letting my mind overcomplicate things :upside_down_face:

Thanks for the reply though! It’s appreciated.

The following code is probably not the solution you’re looking for.
However, it provides a semi-generic enum type, if that’s acceptable.

I'm sharing it in case others find it useful.
package main

Room :: enum {A, B, C}
Level :: enum {D, E, F}

Gen_Enum :: union #no_nil {
	Room,
	Level,
}

Foo :: struct {id: Gen_Enum}
Bar :: struct {into: [dynamic]Foo}

main :: proc() {
    fst: Bar
    append(&fst.into, Foo{Room.A})

    snd: Bar
    append(&snd.into, Foo{Level.D})
}