Using modules as constants

I’m wring a custom Ecto Type that behaves like an enum type. I have a keyword list of atoms => integers.

I realised I can use Elixir Modules (which are really just atoms) for my keys, instead regular atoms. I’m not sure if this is poor form though.

To me, using modules 1) looks more important and obvious that acceptable values are limited in scope and 2) provides some chance for correct code suggestion.

Since they’re “just atoms”, I don’t believe doing this incurs any more performance penalty than I otherwise would? At the same time, passing regular atoms seems a bit more natural to elixir?

I’m not too worried about the wrong atom being inserted into the DB since I check at cast/dump using either methods, it’s more of a stylistic question.

Whats the best practice here? What would you do?

module-as-key

defmodule App.Background.BackgroundJob.Pool do
  # you could probably macro this if you hated the look of the syntax
  defmodule Local do end
  defmodule Remote do end

  @behaviour Ecto.Type
  @pools [{Local, 0}, {Remote, 1}]

  # cast, load, etc...
end

job  = %{
  pool: BackgroundJob.Pool.Local,
  # ...
}

atom-as-key

defmodule App.Background.BackgroundJob.Pool do

  @behaviour Ecto.Type
  @pools [{:local, 0}, {:remote, 1}]

  # possibly have these functions 
  def local, do: :local
  def remote, do: :remote
  
  # cast, load, etc...
end

job  = %{
  pool: BackgroundJob.Pool.local,
  # ...
}

# or

job  = %{
  pool: :local,
  # ...
}
1 Like