gmile
Advice to avoid simple transitive compile-time dependency
I am trying to understand why transitive compile-time dependency is there, and what’s a good strategy to remove it. The mix app for example below is available here.
In a nutshell, I have these 3 modules:
# a.ex
defmodule A do
import B, only: [valid_string: 1]
def check(string) when valid_string(string), do: "OK"
end
# b.ex
defmodule B do
defguard valid_string(string) when string in ~w(read write)
def by_the_way do
C.something()
end
end
# c.ex
defmodule C do
def something do
IO.puts("Just passing by")
end
end
Dependencies from this module form a what’s known as transitive compile-time dependency. This can be confirmed by running mix href command:
mix xref graph --label compile-connected
Output:
lib/a.ex
└── lib/b.ex (compile)
If I remove by_the_way function from module B, mix xref no longer reports a transitive compile-time dependency. Could someone explain to me why A transitively depends on C, even though A is only interested in importing the macro from B, and doesn’t really care about the function by_the_way or its implementation?
What’s a good strategy to remove such transitive compile time dependency? Is it like separating macros and functions in different modules?
Marked As Solved
josevalim
Elixir tracks dependencies at the module level. One common approach to address this is to define constants (which you may access at compile-time, such as invoice_states) and guards that are used across multiple modules into a separate module that only defines constants/guards (and does not call anything else).
Also Liked
hauleth
Because compiler do not know (and in general sense it cannot know) that A do not depend on B.by_the_way. Phoenix generates module that is perfect example of that:
def module MyAppWeb do
defmacro __using__(name) do
apply(__MODULE__, name, [])
end
# …
end
This shows that calling macro can call any function within our module.
It can:
defmodule Foo do
defguard is_foo(a) when foo(a)
defmacro foo(a) do
by_the_way()
quote do: true
end
def by_the_way, do: C.something()
end
dimitarvp
JEG2
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex









