christopheradams / christopheradams/elixir_style_guide

Macro calls placement in a module

Open
#198 1 comment 0 reactions 0 assignees View on GitHub
question
Dominant language
Elixir
Stars
4.4k
Forks
300
PR merge metrics
No merged PRs in 30d

Description

Is there some rule about macro calls placement in a module?

For example imagine such module:

```elixir
defmodule MyApp.Schema do
use Ecto.Schema

import EctoEnum

defenum Status, :status, ~w(active disabled)a
defenum State, :state, ~w(new accepted cancelled finished)a

@required ~w(name number)a
@optional ~w(description)a

@type t() :: %__MODULE__{}
@type id() :: pos_integer()

schema "schema" do
field :name, :string
field :description, :string
field :number, :integer
field :status, Status
field :state, State
end

def changeset(schema, params) do
# ...
end
```

What is correct placement for `defenum` and `schema`?

From my intuition macro calls placement depends on what code they inject.
The `schema` block creates struct so it should have same placement as `defstruct` block while `defenum` creates nested module so should have same placement as `defmodule`.

From such perspective and taking into account current version of this styleguide, module layout should be reorganized in such way:

```elixir
defmodule MyApp.Schema do
use Ecto.Schema

import EctoEnum

@required ~w(name number)a
@optional ~w(description)a

schema "schema" do
field :name, :string
field :description, :string
field :number, :integer
field :status, Status
field :state, State
end

@type t() :: %__MODULE__{}
@type id() :: pos_integer()

defenum Status, :status, ~w(active disabled)a
defenum State, :state, ~w(new accepted cancelled finished)a

def changeset(schema, params) do
# ...
end
```

However if you try to compile something like this it fails with error:

```
== Compilation error in file lib/my_app/schema.ex ==
** (ArgumentError) invalid or unknown type Title for field :title
lib/ecto/schema.ex:2037: Ecto.Schema.check_field_type!/3
lib/ecto/schema.ex:1745: Ecto.Schema.__field__/4
lib/my_app/schema.ex:13: (module)
(stdlib 3.12.1) erl_eval.erl:680: :erl_eval.do_apply/6
```

which means that my intuition about macro calls placement is wrong or at least priority of nested module block should be higher than `defstruct` block.

Maybe this should be discussed in separate issue but [current version](https://github.com/christopheradams/elixir_style_guide/blob/f6fd749c03b35680e69a6461ef58948ca478666b/README.md#module-attribute-ordering) of the guide says that `defstruct` priority is much higher than `defmodule` what looks inconsistent from my point of view because code like this

```elixir
defmodule Example
defstruct origin: __MODULE__, callback_module: Callback

defmodule Callback do
# ...
end
end
```

can't compile even if you use full module name like ` callback_module: __MODULE__.Callback `.

To summarize, this issue has such questions
- Should `defmodule` block have lower priority than `defstruct`?
- What is correct macro calls placement in a module and should this guide contain some rules about it?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.