Practical guide to Julia Enums ↔ Strings
Well, I do this post for the me of the past that spent way to much time on understanding Enums and how to deal with Symbols, Strings and Enums. Coming from Rust, dealing with Julia Enums was a bit frustrating at first.
Enums are basically wrapped integers for some predefined values.
julia> @enum MyEnum A B C
julia> A
A::MyEnum = 0
julia> B
B::MyEnum = 1
julia> C
C::MyEnum = 2
Here, MyEnum
is a type derived from Enum
(Type{<:Enum}
), and A
, B
, and C
are values of that Enum type.
2. Converting Between Enums, Strings, and Symbols
Julia does not provide built-in conversion functions between Enums and Strings, so knowing which method to call is crucial.
Convert an Enum Value to a String
julia> string(Symbol(A))
"A"
Convert an Enum Type to a String Listing All Possible Values
julia> join(string.(instances(MyEnum)), ", ")
"A, B, C"
Convert a String to an Enum Value
julia> eval(Symbol("A"))
A::MyEnum = 0
3. Using Enums in Command-Line Argument Parsing
A common use case is handling program arguments where we need to parse Enum values from command-line inputs and provide users with available options in --help
. Below is a practical example using ArgParse.jl
.
Example: Parsing Command-Line Arguments with Enums
using ArgParse
using Logging
@enum MyEnum A B C
@enum TestEnum begin
TestA
TestB
TestC
end
function enum_values_to_string(enum::Type{<:Enum})::String
return join(string.(instances(enum)), ", ")
end
function enum_to_string(enum_value::Enum)::String
return string(Symbol(enum_value))
end
function string_to_enum(str::String)::Enum
return eval(Symbol(str))
end
function test_enum_and_strings()
@info "Enum values: $(enum_values_to_string(TestEnum))"
@info "Enum to string: $(enum_to_string(A)) of type $(typeof(enum_to_string(A)))"
@info "String to enum: $(string_to_enum("A")) of type $(typeof(string_to_enum("A")))"
end
"Parse program arguments and return the result as a Dict."
function parse_program_args(args)
# Initialize settings
s = ArgParseSettings(description = "Program arguments to Enum values.")
@add_arg_table! s begin
"--log-level", "-l"
help = "Logging level from " * join([string(level) for level in [Debug, Info, Warn, Error]], ", ")
arg_type = Symbol
default = :Info
"--my-enum", "-m"
help = "My enum from " * enum_values_to_string(MyEnum)
arg_type = Symbol
default = :A
"--test-enum", "-t"
help = "Test enum from " * enum_values_to_string(TestEnum)
arg_type = Symbol
default = :TestA
end
pargs = parse_args(args, s)
return Dict(
key => (val isa Symbol ? eval(val) : val) for (key, val) in pargs
)
end
# Initialize logger with log level from arguments
function initialize_logger(log_level::LogLevel)
global_logger(ConsoleLogger(log_level))
end
# Example usage of logger
function main(args)
parsed_args = parse_program_args(args)
initialize_logger(parsed_args["log-level"])
@debug "Logger initialized"
test_enum_and_strings()
# Print parsed arguments
@info "Parsed arguments:"
for (key, val) in parsed_args
@info "$key: $val of type $(typeof(val))"
end
end
main(ARGS)
How This Works:
enum_values_to_string(MyEnum)
: Converts an Enum type into a string listing all possible values.enum_to_string(A)
: Converts an Enum value into a string.string_to_enum("A")
: Converts a string back into an Enum value.parse_program_args(args)
: UsesArgParse.jl
to handle Enums in command-line arguments.- The
main
function initializes a logger and processes command-line arguments.
Example Usage in the Terminal
julia enums.jl -h
Output:
usage: enums.jl [-l LOG-LEVEL] [-m MY-ENUM] [-t TEST-ENUM] [-h]
Program arguments to Enum values.
optional arguments:
-l, --log-level LOG-LEVEL
Logging level from Debug, Info, Warn, Error
(type: Symbol, default: :Info)
-m, --my-enum MY-ENUM
My enum from A, B, C (type: Symbol, default:
:A)
-t, --test-enum TEST-ENUM
Test enum from TestA, TestB, TestC (type:
Symbol, default: :TestA)
-h, --help show this help message and exit
Another example:
julia enums.jl -l Debug -m B
Output:
┌ Debug: Logger initialized
└ @ Main ~/code/phd/phd_plots/src/enums.jl:66
[ Info: Enum values: TestA, TestB, TestC
[ Info: Enum to string: A of type String
[ Info: String to enum: A of type MyEnum
[ Info: Parsed arguments:
[ Info: log-level: Debug of type Base.CoreLogging.LogLevel
[ Info: test-enum: TestA of type TestEnum
[ Info: my-enum: B of type MyEnum
Conclusion
Enums in Julia are lightweight and efficient but require some manual conversions when dealing with Strings and Symbols. By implementing helper functions, we can seamlessly integrate Enums into applications, particularly for command-line parsing.
Note that many discussions and packages are trying to deal with some possible issues you might have, especially is you need to use enum values multiple times for instance and avoid name collision.
See also:
How can I determine the name of an enum value?
Solving the drawbacks of @enum
Encapsulating enum access via dot syntax
ANN: EnumX.jl – improved enums for Julia
If you have other ways to work with Enums in Julia efficiently, feel free to share!