BlitzMax

BlitzMax

  • Downloads
  • Docs
  • API
  • Resources
  • About

›Language

Setup

  • Getting Started
  • Win32
  • Linux
  • macOS
  • Android
  • iOS
  • Raspberry Pi
  • NX (Switch Homebrew)
  • Custom Settings

Tutorials

  • Beginners Guide
  • OOP Tutorial
  • Network Programming
  • TCP Socket Programming

Language

  • Arrays
  • Basic Compatibility
  • Collections
  • Comments
  • Conditional Compiling
  • Constants
  • Data Types
  • Debugging
  • Enums
  • Exceptions
  • Expressions
  • Functions
  • Identifiers
  • Literals
  • Modules
  • Objects
  • Program Flow
  • Slices
  • Strings
  • User Defined Types
  • Variables
  • Advanced Topics

    • Interfacing With C
    • Memory Management
    • Pointers
    • Custom Pre/Post Compilation Scripts
    • Creating DLLs

Tools

  • MaxIDE
  • BlitzMax Make (bmk)
  • BlitzMax Compiler (bcc)
Edit

Enums

Introduction

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 example, EDay.Sunday is associated with the value 0, EDay.Monday with 1, and so on.

Using Enums

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 Ordinal() method:

Print EMonth.May.Ordinal()

Would print 4.

The ToString() method returns a String representation of the enum element:

Print EMonth.Sep.ToString()

Would print Sep.

The Values() function returns an array of all elements:

For Local month:EMonth = Eachin EMonth.Values()
    Print month.ToString() + " = " + month.Ordinal()
Next

Assigning Values

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 16.

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 powers of 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_SOFT, 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, for example: -1 or 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

Notice that we no longer need to Throw on unsupported values of set because we know that only the values specified by the Enum will ever be used.

← DebuggingExceptions →
  • Introduction
  • Using Enums
  • Assigning Values
  • Bit Flag Enums
  • Enum vs Const
BlitzMax
Docs
Getting StartedDownloadsAbout
Community
ResourcesSyntaxBomb Forums
More
GitHubStarChat on Discord
Copyright © 2023 Bruce A Henderson