gmile

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

josevalim

Creator of Elixir

You can print the previous comment in case it has any persuasive power :slight_smile:

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

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

josevalim

Creator of Elixir

The only reason you are doing it is to work around a compiler behaviour and that to me is a smell. :slight_smile:

Where Next?

Popular in Questions Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New

Other popular topics Top

joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

We're in Beta

About us Mission Statement