Using the "Use" Elixir Macro

Deankinyua

Deankinyua

yesterday

Suppose you have the following module directives in your current module:

  import Ecto.Query
  import Pgvector.Ecto.Query, only: [l2_distance: 2]

  alias MyApp.Podcasts.Episode
  alias MyApp.Prompts.PodcastEpisode
  alias MyApp.Prompts.UserQuestion
   
  require Logger

Another module called MyApp.Subscriber is using the same exact directives. You don’t want to violate the principle of DRY (Don’t Repeat Yourself) and hence you figure out that you do not want to do the same thing in the Subscriber module. What can you do about this?

Here is where some basic Metaprogramming skills might come into play. Metaprogramming is basically using code to write code.A combination of quote and use macro in Elixir can be used for exactly that. Anytime you use a specific module, you are basically calling its Module._using_() macro.

To eradicate this repetition, define a module e.g MyApp.Meta then :

defmodule MyApp.Meta do
  defmacro __using__(_options) do
    quote do
      import Ecto.Query
      import Pgvector.Ecto.Query, only: [l2_distance: 2]

      alias MyApp.Podcasts.Episode
      alias MyApp.Prompts.PodcastEpisode
      alias MyApp.Prompts.UserQuestion
      
      require Logger
    end
  end
end

Quote/2 returns an abstract representation (Abstract Syntax Tree) rather than the expression itself.

Then anywhere you need this directives just do :

  use MyApp.Meta