I would definitely go for the approach from @michalmuskala. One problem with maps is that it only supports one way conversion (converting a const into an integer). If you need to convert an integer into a const, you’ll have to build a reversal map. This can be easily done, even during compilation time, but then the code becomes as complex if not more than Michal’s version.
Moreover, I’m not completely sure whether this map is stored in the so called “constant pool”, and if it’s not, then the performance might suck. But even if this is not the case, my previous point stands, and I would personally go for Michal’s solution.
Using that approach, you could have something like:
defmodule Const do
# Michal's snippet:
values = [source_lvl1_api: 301023, ...]
for {key, value} <- values do
def encode(unquote(key)), do: unquote(value)
def decode(unquote(value)), do: unquote(key)
end
end
And now you can do e.g. Const.encode(:source_lvl1_api)
, or Const.decode(301023)
to perform atom ↔ integer conversions.
So what Michal is trying to tell you is that as soon as you take some input from say HTTP request, or the database, you invoke Const.decode
to convert it into an atom. Then in the rest of your code, you just deal with atoms (e.g. :source_lvl1_api
), so the code is ridden of magical numbers. Likewise, if you need to send a response to some client, or store to the database, you perform Const.encode
to convert the atom into a corresponding integer.