An Enum is an efficient way to define a set of constants that can be assigned to variables. Say, for example, you'd like to represent the days of the week. Since this is a fixed set of seven possible values, you could define those values within an Enum :
Enum EDay Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday End Enum
Comma separators are optional, and elements can be placed on separate lines.
Enum ESequence Morning Afternoon Night End Enum
By default, the underlying type of an enum element is an Int, but you can specify a different numeric type by using the standard type declaration syntax, as shown in the following example. Valid integral numeric types that can be assigned as a type include, Byte, Short, Int, UInt, Long, ULong and Size_T.
Enum EMonth:Byte Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec End Enum
When you do not specify any values for the elements, the default is to assign it the index in
the list of elements, starting from
0. So, from the
EDay.Sunday is associated
with the value
1, and so on.
You assign an enum value to a variable just as you would any other type:
Local meetingDay:EDay = EDay.Monday
A variable declared as a particular type of Enum can only be assigned to enum elements of that kind.
meetingDay = EDay.Wednesday ' good meetingDay = EMonth.Aug ' error meetingDay = 3 ' error
To retrieve the numeric value for a particular enum element, you can use the
ToString() method returns a String representation of the enum element:
Values() function returns an array of all elements:
For Local month:EMonth = Eachin EMonth.Values() Print month.ToString() + " = " + month.Ordinal() Next
Rather than using just the default values, you can also assign any constant value (or something that will evaluate to a constant value at compile time) to the elements of an Enum.
Enum EMachineState PowerOff = 0 Running = 5 Sleeping = 10 Hibernating = Sleeping + 5 End Enum
Subsequent elements that do not specify a value, increment from the preceding entry. So if the preceding element
had a value of
15, the next would automatically have the value
Bit Flag Enums
You can use an Enum to define bit flags, which enables an instance of the Enum to store any combination of the values that are defined in its elements.
You create a bit flags enum by applying the
Flags modifier to the Enum declaration,
defining the values appropriately so that standard bitwise operations can be performed on them.
In the following example, an Enum called EDays is defined with the Flags modifier. Each
value is automatically assigned the next greater power of
2, starting at
1. This enables you
to create an
EDays variable whose value is
EDays.Tuesday | EDays.Thursday.
SuperStrict Framework brl.standardio Local meetingDays:EDays = EDays.Tuesday | EDays.Thursday Print meetingDays.ToString() Enum EDays Flags Sunday Monday Tuesday Wednesday Thursday Friday Saturday End Enum
To set a flag on an enum, use the bitwise or operator (
|) as shown in the following example:
' Initialize with two flags using bitwise Or. meetingDays = EDays.Tuesday | EDays.Thursday ' Set an additional flag using bitwise Or. meetingDays :| EDays.Friday Print "Meeting days are " + meetingDays.ToString() ' Output: Meeting days are Tuesday|Thursday|Friday ' Remove a flag using bitwise XOr. meetingDays :~ EDays.Tuesday Print "Meeting days are " + meetingDays.ToString() ' Output: Meeting days are Thursday|Friday
To determine whether a specific flag is set, use a bitwise AND operation (
&), as shown in the following example:
' Test value of flags using bitwise AND. Local test:Int = (meetingDays & EDays.Thursday) = EDays.Thursday If test Then Print "Thursday is a meeting day." Else Print "Thursday is not a meeting day." End If ' Output: Thursday is a meeting day.
Bit flag enums can also have their values specified. It is generally advised to make the values
2, so that you can apply bitwise operations to them. Default values for elements will
always be a power of
2, the next element being the next logical power of
2 higher than the previous entry.
SuperStrict Framework brl.standardio For Local attackType:EAttackType = EachIn EAttackType.Values() Print attackType.ToString() + " = " + attackType.Ordinal() Next Enum EAttackType Flags Melee Fire Ice = $8 Poison End Enum
Because bit flags are limited to the number of bits for a given type (e.g. 8 bits for a Byte, 32 bits for an Int), you need to ensure that the type you use for a bit flag Enum has enough bits for all the elements you require.
If you try to use more bits than the type allows, the compile will fail with an appropriate error message.
Enum vs Const
As well as making the code easier to read, by using an Enum instead of a set of Const values, we can let the compiler ensure that only the specific set of values defined by the Enum be used.
In the following example, we define a set of consts to record the types of available tyres a car can use:
SuperStrict Framework brl.standardio Local car:TCar = New TCar TPitstop.ChangeTyre(car, TYRE_SOFT) Const TYRE_SOFT:Int = 0 Const TYRE_MEDIUM:Int = 1 Const TYRE_HARD:Int = 2 Const TYRE_INTER:Int = 3 Const TYRE_WET:Int = 4 Type TPitstop Function ChangeTyre(car:TCar, set:Int) If car.tyreSet = set And set <> TYRE_WET Then Throw"Can't change to same kind of tyre" End If Local s:String Select set Case TYRE_SOFT s = "Soft" Case TYRE_MEDIUM s = "Medium" Case TYRE_HARD s = "Hard" Case TYRE_INTER s = "Inter" Case TYRE_WET s = "Wet" Default Throw "Not a valid tyre choice" End Select car.tyreSet = set Print "Changing to " + s End Function End Type Type TCar Field tyreSet:Int = TYRE_MEDIUM End Type
We expect that users of our code will diligently use the defined constants,
instead of numbers –
TYRE_MEDIUM and so on.
The problem lies in the fact that someone may decide not to use the constants defined
by us and may submit an invalid number as an argument of our function,
10. In this case, if the function does not check for
invalid value, it will likely result in incorrect behaviour.
To avoid this problem we can replace the constants with an Enum, thereby constraining the values that can be passed into the function :
SuperStrict Framework brl.standardio Local car:TCar = New TCar TPitstop.ChangeTyre(car, ETyre.Soft) Enum ETyre Soft Medium Hard Inter Wet End Enum Type TPitstop Function ChangeTyre(car:TCar, set:ETyre) If car.tyreSet = set And set <> ETyre.Wet Then Throw"Can't change to same kind of tyre" End If Local s:String Select set Case ETyre.Soft s = "Soft" Case ETyre.Medium s = "Medium" Case ETyre.Hard s = "Hard" Case ETyre.Inter s = "Inter" Case ETyre.Wet s = "Wet" End Select car.tyreSet = set Print "Changing to " + s End Function End Type Type TCar Field tyreSet:ETyre = ETyre.Medium End Type