3.1.1. Enums

type enum

Enums in Dao provide a bit more functionality than enums in other languages, and can be defined in multiple different ways.

3.1.1.1. State Enums

The first method for defining enums will be the most familiar to users of C-like languages with enum support.

enum MyEnum
{
        AA    , # 0
        BB = 3, # 3
        CC      # 4
}

The type of enum shown here is what Dao refers to as a “State” enum, and is thus intended to indicate unique values. State enums are concrete and cannot be combined; attempting to add together two state enums is a compiler error.

As the comments indicate, they work very much like C/C++ enums: the first index is assigned the value of 0, unless another value is explicitly assigned to it, and each subsequent value is either explicitly assigned or is assigned to a number one greater than the previous value.

Unlike C, however, the values of enums are not dumped directly into the enclosing namespace. Instead, they are treated as static fields of the enum type, meaning they have a well-defined scope. So, to access this enum, your code would look like this:

Since this is a state enum, the following would be an error:

note:Trailing commas are allowed on the last value of an enum.

3.1.1.2. Flag Enums

enum MyEnum
{
        AA    ; # 1 (0b00000001)
        BB = 3; # 3 (0b00000011)
        CC      # 6 (0b00000110)
}

Flag enums look very similar to state enums, so the difference may not be immediately obvious: the difference between the definitions of a flag enum and a state enum is that flag enum values are separated by a semicolon instead of a comma. And as you might expect from the definition of a state enum, the primary functional difference is that flag enums can be combined, while state enums cannot. In this case, you’ll also notice that the value of AA and CC have changed between the two examples - with flag enums, instead of starting at 0 and incrementing each value by one, it instead starts at 1 and left shifts each value by one position. Thus, if no explicit numbering is given:

enum MyEnum
{
        AA; # 1 (0b00000001)
        BB; # 2 (0b00000010)
        CC  # 4 (0b00000100)
}

Since these symbols can be combined freely, and increment by left-shifting, they are ideal for use as flags. The following operations are given special treatment by flag enums:

Operation Result
A + B

A and B are combined. This operation performs a binary OR (|) on the two values and returns the union of the bits.

Equivalent to A | B

A - B

Bits in B are unset in A This operation removes the bits in B from the value A and returns the difference between A and B.

Equivalent to A & ~B

A in B

Checks if all bits in A are also present in B

Equivalent to A & B == A

A not in B

Checks if any bits in A are not present in B

Equivalent to A & B != A

Thus, flag enums are treated a bit differently than in other languages - in Dao, flags are first-class citizens.

enum Permissions
{
        CanRead;
        CanWrite;
        CanExecute
}

myFile.permissions = Permissions.CanRead + Permissions.CanExecute;

All enums can be implicitly or explicitly converted to and from int.

todo:Presently there is a bug where bitwise operations on enum literals do not work. If you need to perform bitwise operations on enums literals, the solution is to either store them into variables, or cast them to ints.
enum MyEnum
{
   A;
   B;
   C;
}

var intersection = MyEnum.A & MyEnum.C; #DOES NOT WORK.

var AB = MyEnum.A + MyEnum.B;
var BC = MyEnum.B + MyEnum.C;
var intersection = AB & BC;  #Works

var intersection = (int)MyEnum.A & (int)MyEnum.C;  # Works, but returns an int
                                                   # either specify type of var intersection,
                                                   # or cast the result to MyEnum
note:Because enums are stored as a 32-bit integer (even on 64-bit architectures), flag enums are limited to 32 values.
note:Just like trailing commas in state enums, trailing semicolons are allowed on the last value of a flag enum.

3.1.1.3. Enum Shorthand

When the type of the enum you’re using is known statically, it’s possible to use shorthand to reduce typing by leaving out the enum type name. This is ONLY possible in a context where the enum’s type is static and known; if the type is not known, this syntax always gets a value of 0 from an anonymous enum type. To use this shorthand, simply replace the name of the type with the $ symbol:

enum MyStateEnum
{
        AA = 1,
        BB,
        CC,
}

enum MyFlagEnum
{
        AA;
        BB;
        CC;
        DD;
}

var state : MyStateEnum;
var flags : MyFlagEnum;
var flags2 : MyFlagEnum;
var someEnum : any;

state = $AA; # 1 - This variable is known to be of type MyStateEnum.
flags = $BB | $CC; # 6 - This variable is known to be of type MyFlagEnum
someEnum = $DD; # 0 - Unknown type results in an anonymous enum with one value (DD) equal to 0

3.1.1.4. Inline Enum Declaration

Enum types can be created ad-hoc for variables, function parameters, and return types using the inline enum declaration:

var a : enum<on,off> = $on;
routine SetPermissions( permissionMask : enum<CanRead;CanWrite;CanExecute> = $CanRead )
{
        # ...
}

The rules for the inline enum syntax are the same as the normal enum syntax: comma-separated means state enum, while semicolon-separated means flag enum.

3.1.1.5. Using Enums in Switch Statements

Enums are particularly effective when used in switch statements. When performing a switch statement on a value of known enum type, the dao compiler is able to optimize the operation heavily by performing a table lookup instead of branching.

enum MyEnum
{
        AA,
        BB,
        CC
}

var e1 : myEnum = $AA;

switch( (any)e1 ){
case MyEnum::AA : ...
case MyEnum::BB : ...
case MyEnum::CC : ...
}

switch( e1 ){
case $AA : ...
case $BB : ...
case $CC : ...
}

Both of these examples can take advantage of this performance optimization because in both cases the type is known by the compiler. In the first case, the compiler can infer the type based on the list of case statements, and in the second, the compiler is able to determine the type based on the static typing of var e1.