Popularity
87 Stars
Updated Last
2 Months Ago
Started In
March 2022

EnumX.jl

CI codecov

This is what I wish Base.@enum was.

Usage

EnumX exports the macro @enumx, which works similarly to Base.@enum, but with some improvements.

The main drawback of Base.@enum is that the names for instances are not scoped. This means, for example, that it is inconvenient to use "common" names for enum instances, and it is impossible to have multiple enums with the same instance names.

EnumX.@enumx solves these limitations by putting everything behind a module scope such that instances are hidden and instead accessed using dot-syntax:

julia> using EnumX

julia> @enumx Fruit Apple Banana

julia> Fruit.Apple
Fruit.Apple = 0

julia> Fruit.Banana
Fruit.Banana = 1

Fruit is a module -- the actual enum type is defined as Fruit.T by default:

julia> Fruit.T
Enum type Fruit.T <: Enum{Int32} with 2 instances:
 Fruit.Apple  = 0
 Fruit.Banana = 1

julia> Fruit.T <: Base.Enum
true

Another typename can be passed as the first argument to @enumx as follows:

julia> @enumx T=FruitEnum Fruit Apple

julia> Fruit.FruitEnum
Enum type Fruit.FruitEnum <: Enum{Int32} with 1 instance:
 Fruit.Apple = 0

Since the instances are scoped into a module, tab-completion is obtained "for free", which helps a lot with discoverability of the instance names:

julia> @enumx Fruit Apple Banana

julia> Fruit.<TAB>
Apple Banana T

Since the only reserved name in the example above is the module Fruit we can create another enum with overlapping instance names (this would not be possible with Base.@enum):

julia> @enumx YellowFruit Banana Lemon

julia> YellowFruit.Banana
YellowFruit.Banana = 0

Instances can be documented like struct fields. A docstring before the macro is attached to the module Fruit (i.e. not the "hidden" type Fruit.T):

julia> "Documentation for Fruit enum-module."
       @enumx Fruit begin
           "Documentation for Fruit.Apple instance."
           Apple
       end

help?> Fruit
  Documentation for Fruit enum-module.

help?> Fruit.Apple
  Documentation for Fruit.Apple instance.

@enumx allows for duplicate values (unlike Base.@enum):

julia> @enumx Fruit Apple=1 Banana=1

julia> Fruit.T
Enum type Fruit.T <: Enum{Int32} with 2 instances:
 Fruit.Apple  = 1
 Fruit.Banana = 1

julia> Fruit.Apple
Fruit.Apple = Fruit.Banana = 1

julia> Fruit.Banana
Fruit.Apple = Fruit.Banana = 1

@enumx lets you use previous enum names for value initialization:

julia> @enumx Fruit Apple Banana Orange=Apple

julia> Fruit.T
Enum type Fruit.T <: Enum{Int32} with 3 instances:
 Fruit.Apple  = 0
 Fruit.Banana = 1
 Fruit.Orange = 0

Other than that, functionality should be comparable to Base.@enum:

  • Base type specification (defaults to Int32):

    julia> @enumx Fruit::UInt8 Apple Banana
    
    julia> typeof(Integer(Fruit.Apple))
    UInt8
  • Specifying values with literals or expressions (if not specified, defaults to the value of the previous instance + 1):

    julia> @enumx Fruit Apple=4 Banana=(1 + 5) Orange
    
    julia> Fruit.T
    Enum type Fruit.T <: Enum{Int32} with 3 instances:
     Fruit.Apple  = 4
     Fruit.Banana = 6
     Fruit.Orange = 7
  • Definition with begin/end block:

    julia> @enumx Fruit begin
               Apple
               Banana
               Orange
           end

See also

Community discussions

Related packages

  • CEnum.jl: C-compatible Enums.
  • SuperEnum.jl: Similar approach as EnumX, but doesn't give you Base.Enums.
  • NamespacedEnums.jl: Discontinued package similar to EnumX, which gave me the idea to let user override the default .T typename.