From baremodule to Dict


#1

Hello,

I defined a baremodule

baremodule Return
const INVALID_CMD = 0x00
const CMD_FINISHED = 0x01
end

I would like to get a Dict from this module with keys being 0x00 and 0x01 (and more …)

How can I achieve this task?

Kind regards


#2

You can do this with names and getfield, but using a module in this way is very uncommon and probably not a good idea. What are you trying to do, and why do you need a module to store these constants?


#3

I sometimes overload enumerate to list all the constants in a baremodule:

import Base.enumerate
function enumerate(::Type{T}, mod) where T
    n = names(mod,true)
    v = map(x->getfield(mod,x),n)
    filter(v->typeof(v)==T,v)
end

julia> enumerate(UInt8,Return)
2-element Array{Any,1}:
0x01
0x00

But you could use an enum too.


#4

I noticed this kind of usage in

What I like is that I need to do Return.CMD_FINISHED to access 0x01 constant

With Enum,

julia> @enum ReturnE::UInt8 INVALID_CMD = 0x00 CMD_FINISHED = 0x01
julia> ReturnE
Enum ReturnE:
INVALID_CMD = 0
CMD_FINISHED = 1

One problem, is that despite I defined type of UInt8, Enum doesn’t seem to keep a track of it (see 0, 1, instead of 0x00 and 0x01).

Moreover I can access directly to INVALID_CMD without preceding with ReturnE
which is not something I like

With Enum, accessing to a given key with a value can be done using ReturnE[0x01][1] and I get CMD_FINISHED::ReturnE = 1

What I don’t like with enumerate approach is that we get an Array of Any.

I just need to be able to get :CMD_FINISHED from 0x01


#5

Ah, I see. Your UInt8 declaration in the @enum is working, it’s just that Julia is displaying the value by converting it to a plain Int. I’m honestly not sure why that’s done, but it’s possible to prove that your enum values really are UInt8s:

julia> @enum ReturnE::UInt8 INVALID_CMD = 0x00 CMD_FINISHED = 0x01

julia> sizeof(CMD_FINISHED)
1

julia> Base.Enums.basetype(typeof(CMD_FINISHED))
UInt8

sizeof gives the size in bytes, so CMD_FINISHED is stored in exactly 1 byte.

It’s perfectly reasonable to want a namespace for your enum. How about the following:

julia> module Return

       export ReturnCodes
       @enum ReturnCodes::UInt8 INVALID_CMD=0x00 CMD_FINISHED=0x01

       end
Return

julia> sizeof(Return.CMD_FINISHED)
1

julia> Return.ReturnCodes[0x01]
1-element Array{Return.ReturnCodes,1}:
 CMD_FINISHED


#6

Thanks a lot @rdeits!

Maybe we should open an issue about Enum display with UInt8?

I also wonder how to get CMD_FINISHED value as UInt8 without specifying type.

Is Base.Enums.basetype(Return.ReturnCodes)(Return.CMD_FINISHED) the simplest approach?

===

About baremodule approach, thanks to @jonathanBieler suggestion I implemented 2 functions

function getSymbols(mod::Module, value)
  vct = Vector{Symbol}()
  for n in names(mod, true)
    if n != Symbol(mod)
      v = getfield(mod, n)
      if v == value
        push!(vct, n)
      end
    end
  end
  vct
end

function getDict(mod::Module, t::Type)
  d = Dict{Symbol,t}()
  for n in names(mod, true)
    if n != Symbol(mod)
      v = getfield(mod, n)
      if !haskey(d, n)
        d[n] = v
      else
        error("$n is not unique - $(d[n]) $v")
      end
    end
  end
  d
end

I posted it here but I think I will in fact use the Enum approach (bracketed version) as it also insure that values are unique at creation.

module Return
  @enum(ReturnCodes::UInt8,
    CMD_FINISHED   = 0x01,
    INVALID_CMD    = 0x00,
  )

  function code(val)
    Symbol(Return.ReturnCodes[val][1])
  end

end

PS: edit 2018-06-06 Julia 0.7 now supports begin/end for enum



#7

Issue opened at https://github.com/JuliaLang/julia/issues/27025 about display of Enum with UInt8


#8

I’ve also found at times that name-spaced enumerations would be nice. Mainly because otherwise the items seem a bit polluting on the name-space and also are a hassle to export (or rather not). I like @rdeits’s solution (but is the export needed?).


#9

Nope, export isn’t necessary. I just thought it might be convenient.