I’m refactoring some parts of a codebase that do some compile-time magic, in order to reduce the number of compile-time dependencies between modules. One thing I don’t fully get is when nominal references to other modules/aliases in module attributes create a compile-time dependency.
I have a minimal example here (compiling with elixir 1.15.7-otp-26)
If I have these two modules:
defmodule Trace.Submodules.Submodule do
end
and
defmodule Trace do
alias Trace.Submodules
@attribute Submodules.Submodule
@attribute Submodules.DoesNotExist
@attribute [Submodules.Submodule]
@attribute [Submodules.DoesNotExist]
@attribute to_string(Submodules.Submodule)
@attribute to_string(Submodules.DoesNotExist)
@attribute to_string(Submodules.Submodule) <> to_string(Submodules.DoesNotExist)
@attribute (& &1).(Submodules.Submodule)
def attribute, do: @attribute
end
When I run mix xref trace lib/trace.ex --label compile
it shows Trace
three places where there are compile-time dependencies on Trace.Submodules.Submodule
→ precisely where there are function calls wrapping Subodules.Submodule
, but not a direct reference or just wrapping in a list.
lib/trace.ex:8: alias Trace.Submodules.Submodule (compile)
lib/trace.ex:10: alias Trace.Submodules.Submodule (compile)
lib/trace.ex:11: alias Trace.Submodules.Submodule (compile)
It’s weirder because I do the exact same operations for Submodules.DoesNotExist
, which doesn’t exist, and there’s no problem. Is it the case the compiler assumes the alias can be used as a module by the function at compile-time, so it places a compile-time dependency on it?
Asking bc the reason behing the behaviour impacts how I’ll approach refactoring. Any help appreciated!