gmile
Strategy to avoid particular transitive compile-time dependency
As part of Understanding a spike in app compilation time, I’m trying to remove compile-time dependency that’s based on defguard macro.
With the code below, Elixir reports a transitive compile-time dependency:
mix xref graph --label compile-connected
lib/example1.ex
└── lib/guards.ex (compile)
How would one go about change the code to avoid the transitive dependency, while (ideally) preserving the defguard macros?
For context, this is a simplified example of production code. The reason lib/guards.ex is a separate file is code re-use - it’s typically included into other modules to offer the guards.
The code looks like this (repo is available here, for reference):
# lib/example1.ex
defmodule Example1 do
import Example1.Guards
def user(user) when is_admin(user), do: IO.puts("This user is an admin: #{inspect(user)}")
def user(user) when is_customer(user), do: IO.puts("This user is a customer: #{inspect(user)}")
end
# lib/guards.ex
defmodule Example1.Guards do
defguard is_admin(user) when is_struct(user, Example1.Admin) == "admin"
defguard is_customer(user) when is_struct(user, Example1.Customer) == "customer"
end
# lib/admin.ex
defmodule Example1.Admin do
defstruct role: :admin
end
# lib/customer.ex
defmodule Example1.Customer do
defstruct role: :customer
end
Since both defguard and is_struct(anyVariable, AnyModule) are not supposed to make any function calls on the AnyModule - maybe there’s no reason to report a compile-time dependency in such case, is there?
Marked As Solved
josevalim
You can print the previous comment in case it has any persuasive power ![]()
BUT GOOD NEWS
It will no longer be required from Elixir v1.15. I realized that patterns and guards cannot add runtime dependencies to modules because they can never call said modules, so the compile-connected dependency should fully disappear in v1.15.
Thanks everyone for the helpful discussion!
Also Liked
LostKobrakai
@admin Module.concat(["Example1", "Admin"])
@customer Module.concat(["Example1", "Customer"])
defguard is_admin(user) when is_struct(user, @admin)
defguard is_customer(user) when is_struct(user, @customer)
This seems to work. Module.concat is also what you’d commonly see in macros for those issues.
josevalim
The only reason you are doing it is to work around a compiler behaviour and that to me is a smell. ![]()
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
- #api
- #forms
- #metaprogramming
- #security
- #hex










