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 = 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
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.Enum
s. - NamespacedEnums.jl: Discontinued
package similar to EnumX, which gave me the idea to let user override the default
.T
typename.