Retrieving an instance of an enum using a string

lewis
Sat, 15 May 2021 03:33:25 +0000
General Usage

This has been posed, sort of, several times in Discourse or stackoverflow.

For this example: @enum condition nil=5 mild sick severe

It is easy to get the enum with an integer:

julia> condition(5)
nil::condition = 5

I have a need to convert a string that matches the enum’s appearance to the actual enum: to go from “nil” to nil::condition = 5.

Here are 2 versions of strtoenum. Which of these would be preferred?

First, using the function Base.Enums.namemap, which is not exported.

function strtoenum(enumgrp::Type{<:Enum{T}}, str::String) where {T<:Integer}
    dict = Base.Enums.namemap(enumgrp)
    found = -1
    srch = Symbol(str)
    for (k,v) in dict
        if v == srch
            found = k
            break
        end
    end
    if found != -1
        return enumgrp(found)
    end
end

julia> @btime strtoenum(condition, "nil")
  68.191 ns (0 allocations: 0 bytes)
nil::condition = 5

Second, using instances, which is documented, rather than namemap:

function strtoenum2(enumgrp::Type{<:Enum{T}}, str::String) where {T<:Integer}
    srch = Symbol(str)
    found = -1
    for val in instances(enumgrp)
        if srch == Symbol(val)
            found = val
            break
        end
    end
    if found != -1
        return found
    end
end

julia> @btime strtoenum2(condition, "nil")
  71.731 ns (0 allocations: 0 bytes)
nil::condition = 5

Break-even in performance; no allocations.

Questions:

1. Neither raises an error if the input string doesn’t match the name of the enum–instead returning nothing. Should a value error be raised? nothing is probably going to cause an error if you try to use the return value for anything.

2. Which is preferred?

3. Is this worth a PR to enum? It’s way slower than condition(5), which has nothing to do. The cost is linear in the number of instances in the enum set.

7 posts - 4 participants