Elixir macros - a way to access module attributes

Hi,

I’ve been learning elixir macros for some time and I’m doing so by trying to implement a small library similar in scope to https://github.com/sasa1977/exactor. Basically a set of macros to simplify common GenServer boilerplate.

Here is a simple example how it looks like.

defmodule CounterAgent do
    use Stone.GenServer

    defstart start_link(val \\ 0) do
      initial_state(val)
    end

    defcall get(), state: state do
      reply(state)
    end
end

And then the usage is:

{:ok, pid} = CounterAgent.start_link(5)
CounterAgent.get(pid)

What I wanted to implement as a next step was an option to generate “singleton” GenServers, like that:

defmodule CounterAgent do
    use Stone.GenServer, singleton: CounterAgent

    defstart start_link(val \\ 0) do
      initial_state(val)
    end

    defcall get(), state: state do
      reply(state)
    end
end

So that the server would automatically register under the name CounterAgent so that no pid would need to be supplied to the calls:

CounterAgent.start_link(5)
CounterAgent.get()

The problem I have is about how to propagate the singleton parameter from the __using__ macro to a defcall macro. I can easily set the module attribute @singleton to that value, but then since macros only operate on code, there is no easy way to access the value of module attribute @singleton in a macro. I know that an approach like that works:

defmacro defcall(...) do
  quote do
    if @singleton do
      unquote(def_call_fun(singleton: true))
    else
       unquote(def_call_fun(singleton: false))
    end
  end
end

What is a good way to solve this issue?

1 Like

You’d want to use a Module Attribute. :slight_smile:

1 Like