This is what I wish Base.@enum was.
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 = 1Fruit 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
trueAnother 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 = 0Since 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 TSince 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 = 0Instances 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 = 0Other 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/endblock:julia> @enumx Fruit begin Apple Banana Orange end
Community discussions
- Encapsulating enum access via dot syntax
- Can not reuse enum member in different member
- Solving the drawbacks of
@enum
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
.Ttypename.