Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constant (integer-backed / c-style) enums #529

Open
kengorab opened this issue Dec 31, 2024 · 0 comments
Open

Constant (integer-backed / c-style) enums #529

kengorab opened this issue Dec 31, 2024 · 0 comments

Comments

@kengorab
Copy link
Owner

kengorab commented Dec 31, 2024

Sometimes it's convenient to have c-style enums, which is essentially a limited set of integer values, each with a given name. Enums in Abra can have variants of two different flavors, Constant and Container; Container enums have fields and are a way of modeling disjointed unions whereas Constant enums have no internal data (fields).

Enum variants are represented in memory as a variable-sized data structure whose first property is a 64-bit integer representing the variant index (64 bits is way more than is necessary, but it's done this way for alignment purposes), followed by any of the data needed to be stored for that variant (Constant variants of course have no internal data). In pseudocode:

{
  u64 variant_idx;
  [ptr field_n;]*
}

This proposal has 2 subtopics:

Implicit c-style enums

When given an enum with only Constant variants, do not use any backing data structure to represent the variants and instead just use an integer.

enum FileOpenMode {
  ReadOnly
  WriteOnly
  ReadWrite
}

Under this new proposal, this would result in FileOpenMode.ReadOnly to simply be represented as 0 rather than a structure like { .variant_idx = 0 }. This would be a slight performance boost in certain special cases, but would become especially useful when defining bridging interfaces with c code (like in std/libc.abra).

Explicitly defining ordinal values

In the implicit example above, the variants' ordinal values are 0, 1, and 2 as would be expected. However, it may be desirable to explicitly set the ordinal value. This can be done with an =:

enum FileOpenMode {
  ReadOnly = 0
  WriteOnly
  ReadWrite
  Create = 512
}

In this case, like above ReadOnly, WriteOnly, and ReadWrite are represented as 0, 1, and 2 respectively, but Create is represented as 512. The = 0 on ReadOnly is redundant and unnecessary and should result in a warning (once they exist, see #504).

The right-hand side of the = must be a constant integer literal, and in an enum where such construct is used, no Container variants are allowed. Each ordinal number must also be unique, so the following examples would result in type errors:

enum Foo {
  Bar = 1
  Baz = 1
}

and

enum Foo {
  Bar
  Baz
  Qux = 1 // error, Baz already implicitly has ordinal value 1
}

Functionality

Operations

Such constant enums should have the following comparison operators available: <, <=, >, >=, ==, !=. These operators should work between enum values and also integers. Arithmetic operators are not supported for constant enums.

The binary opertors || and && are supported for constant enums as well and can be used between enum values and integer values, but the resulting expression is of type Int (since the resulting value cannot be guaranteed to be a valid enum value).

Methods

Constant enums will have the following methods automatically defined for them, just by being a constant enum (enums with Container variants will not have these methods):

func fromOrdinal(value: Int): Self?

A static method on the enum itself which can convert an integer value to the enum value. This returns an Option because an invalid ordinal integer may be provided.

func asOrdinal(self): Int

Returns the integer ordinal value of a given enum value.

The toString(self): String, eq(self, other: Self): Bool, and hash(self): Int methods should still function as expected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant