Oliver

Oliver

Macro does not like module attribute?

In file 1:

defmodule Utils.Struct do

  # this is for importing definitions when "use Utils.Struct" is called
  defmacro __using__(_opts) do
    quote do
      import Utils.Struct
    end
  end

  defmacro defstruct_module(struct_name, fields) do
    quote do
      defmodule unquote(struct_name) do
        use Utils.Access
        defstruct unquote(fields)
      end
    end
  end

end

In file 2:

defmodule Statistical.Generator do

use Utils.Struct

@in_files [:in_cause, :out_cause, :start]

defstruct_module(State, @in_files)

Breaks:

warning: undefined module attribute @in_files, please remove access to @in_files or explicitly set it before access
  <some file>: Statistical.Generator.State (module)


== Compilation error in file <some file> ==
** (ArgumentError) struct fields definition must be list, got: nil
    (elixir 1.14.4) lib/kernel/utils.ex:117: Kernel.Utils.defstruct/3

But this works - again file 2:

defmodule Statistical.Generator do

use Utils.Struct

@in_files [:in_cause, :out_cause, :start]
in_files = @in_files

defstruct_module(State, in_files)

By the way, if I use the variable approach instead of the module attribute, than the def blocks of the module in file 2 complain… can’t win? :sweat_smile:

Is this because the it inserts the module attribute verbatim as abstract syntax tree? Is there a construct/pattern to handle this case - like would a bind_quote help?

Thank you!

First Post!

DaAnalyst

DaAnalyst

To use the module attributes in your macro, you’ll need to do it in __before_compile__/1.

Take a look at this upgrade of my library which was done precisely for the same reason
(see the difference between v0.2.0 and v0.1.0) - kudos and thanks to @kip

https://github.com/DaTrader/assigns

Most Liked

josevalim

josevalim

Creator of Elixir

Correct. You could instead first unquote it in its actual scope:

    quote do
      fields = unquote(fields)
      defmodule unquote(struct_name) do
        use Utils.Access
        defstruct fields
      end
    end

Last Post!

DaAnalyst

DaAnalyst

If you look at my lib code, you’ll see that in its first version (0.1.0) it simply relied on the vanilla macros to expand the def assign_* and friends. The problem with that approach was that it could only take a list of atoms and not a module attribute (to which a list of atoms is assigned) because the module attribute was not resolvable at the time of the macro expansion. The __before_compile__/1 approach that was suggested by @kip solved this (as shown in the version 0.2.0) because at the time it expands it can resolve the module attributes, hence the necessary refactoring.

Where Next?

Popular in Questions Top

jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" =&gt; #BSON.ObjectId&lt;58eb1a7a9ad169198c3dXXXX&gt;, "email" =&gt; ...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New

Other popular topics Top

rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 40082 209
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New

We're in Beta

About us Mission Statement