Accessing module attributes without compilation state guarantee

I’m accessing module attributes at compile-time and no guarantee on module compilation state. So I wrote the following:

case Code.ensure_compiled(module) do
  {:module, module} -> module.__info__(:attributes) |> Keyword.get(attribute)
  {:error, :unavailable} -> Module.get_attribute(module, attribute)
  {:error, _} -> :error
end

as the the docs Module — Elixir v1.16.0 state that if the module is not yet compiled you can access with Module.get_attribute/2 but if it is then the module attribute must be registered as :persist and accessed via module.__info__/1. However, in my case statement above I am finding modules that are: {:module, module} = Code.ensure_compiled(module) so they appear to be compiled, yet __info__/1 is not available. In other words, this bombs out:

{:module, module} = Code.ensure_compiled(module)
module.__info__(:attributes)

yet this works:

{:module, module} = Code.ensure_compiled(module)
Module.get_attribute(module, attribute)

I would have expected the first code block to work with __info__/1 as Code.ensure_compiled/1 is saying the module is compiled. And I would have expected the 2nd code block to error as I shouldn’t be able to use Module.get_attribute/2 if the code has been compiled.

I’m assuming that Code.ensure_compiled is not the best way to do this. Is there another way I can ensure the compilation state of the module to use the correct accessor method to get the module attribute?

2 Likes