Skip to content

:for creates compile-time dependencies when defining protocol implementations #11706

@ribanez7

Description

@ribanez7

Environment

  • Elixir & Erlang/OTP versions (elixir --version): Elixir 1.13.0
  • Operating system: any

Current behavior

:for in protocol implementations creates transitive compile-time dependencies. Here you can see an example, within a basic newly created phoenix app.

Ecto.Schema wrapper:

defmodule ProtoComp.Schema do
  defmacro __using__(_) do
    quote do
      use Ecto.Schema

      @timestamps_opts type: :utc_datetime_usec
    end
  end
end

Schema:

defmodule ProtoComp.Things.Chair do
  use ProtoComp.Schema
  import Ecto.Changeset

  schema "chairs" do
    field :attributes, :string
    field :color, :string

    timestamps()
  end

  @doc false
  def changeset(chair, attrs) do
    chair
    |> cast(attrs, [:color, :attributes])
    |> validate_required([:color, :attributes])
  end
end

Protocol:

defprotocol ProtoCompWeb.UseCases.GrabWith do
  def accessories(thing)
end

Implementation:

defimpl ProtoCompWeb.UseCases.GrabWith, for: ProtoComp.Things.Chair do
  def accessories(_), do: "use your hands"
end

With this setup, when running mix xref graph --label compile-connected the result is that the Chair schema is a transitive dependency for the protocol implementation.

However, if I remove the Ecto.Schema wrapper and use it directly, that compile-time dependency disappears:

defmodule ProtoComp.Things.Chair do
  use Ecto.Schema
  import Ecto.Changeset

  @timestamps_opts type: :utc_datetime_usec

  schema "chairs" do
    field :attributes, :string
  ...
end

There is a thread explaining that issue also in the elixirforum: https://elixirforum.com/t/wrapping-ecto-schema-in-macro-results-in-transitive-compile-time-dependency/46611

And you can check the repo created to reproduce the issue here: https://github.com/ribanez7/protocols_compilation

Expected behavior

:for should not add a compile-time dependency. I expect to run mix xref graph --label compile-connected within a similar setup, using protocols implemented by ecto schemas, and not having them as transitive dependencies.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions