use just calls the __using__ macro on the specified module.

You might have run into that explanation of use but that does not explain much even though that's exactly what it does.

You might have used the use statement in Elixir if you run into using OTP, Phoenix, Ecto or any major library, so did I. But I was confused that what's use , what's the magic happening behind that statement.

In this post we are going to look how use is being used by various Elixir libraries and how it removes the boilerplate that would have been required otherwise.

Lets use use

Elixir has great metaprogramming capabilities and it has macros to generate code at compile time. Wouldn't it be also great if library developers can inject code into your module so that they can decrease the boilerplate for you.

This is where use comes in. When you call use in your module then that modules __using__ macro is called in which the developer can generate whatever code they want. It also takes an arguments list. Let's see an example of it

defmodule AwesomeLibrary do defmacro __using__(_) do quote do def print(s), do: IO.puts(s) end end end

Here we have defined a module in which under __using__ macro we inject a function print/1 which when called prints whatever is passed to it.

defmodule TestLibrary do use AwesomeLibrary end iex(1)> TestLibrary.print("Hello World") Hello World :ok

As you can see that the module TestLibrary has no function print/1 but when we call use AwesomeLibrary it calls the __using__ macro which injects the print/1 function into the TestLibrary module. So in iex calling TestLibrary.print("Hello World") works.

Now let's see some examples of how use is being used in various libraries.

use GenServer

GenServer is a behaviour module which allows you to write process which maintain state and run code synchronously & asynchronously. In Elixir you call use GenServer and implement the relevant behaviour functions you want e.g. init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3 . If you have used GenServer you know that you don't have to define every method of the GenServer, only the one you need. Actually if it were Erlang you would have to implement all the functions whether you want it or not, yet you don't have to do that in Elixir, ever wondered why?

Thanks to use you don't have to. Let's see the __using__ of the GenServer

defmacro __using__(_) do quote location: :keep do @behaviour :gen_server @doc false def init(args) do {:ok, args} end @doc false def handle_call(msg, _from, state) do # We do this to trick dialyzer to not complain about non-local returns. case :random.uniform(1) do 1 -> exit({:bad_call, msg}) 2 -> {:noreply, state} end end @doc false def handle_info(_msg, state) do {:noreply, state} end @doc false def handle_cast(msg, state) do # We do this to trick dialyzer to not complain about non-local returns. case :random.uniform(1) do 1 -> exit({:bad_cast, msg}) 2 -> {:noreply, state} end end @doc false def terminate(_reason, _state) do :ok end @doc false def code_change(_old, state, _extra) do {:ok, state} end defoverridable [init: 1, handle_call: 3, handle_info: 2, handle_cast: 2, terminate: 2, code_change: 3] end end

As you can see that the __using__ macro implements the Erlang behaviour :gen_server and it generates the default implementation of all the required functions and also declares them overridable. This way it reduces the amount of code you need to generate as there will already be a default implementation for the function and GenServer will just work.

You can use the same technique when you create new behaviours.

use Ecto

In Ecto if you want to define the schema you call use Ecto.Model in that module. Here the use Ecto.Model acts as an umbrella module that adds all other relevant libraries so you don't have to add bunch of import statements yourself. Let's see the __using__ of Ecto.Model module.

defmacro __using__(_opts) do quote do use Ecto.Schema import Ecto.Changeset import Ecto.Query, only: [from: 2] import Ecto.Model use Ecto.Model.OptimisticLock use Ecto.Model.Timestamps use Ecto.Model.Dependent use Ecto.Model.Autogenerate use Ecto.Model.Callbacks end end

Here as you can see it's importing bunch of libraries so that you can use the functions in it without prepending with module name and it also further calls use of other module.

use Protobuf

Protobuf is a language independent protocol developed by Google to serialize structured data to send over the wire and then deserialize it, similar to XML but faster and compact.

In Elixir exprotobuf is library that helps in generating code which makes it pretty straight forward for you to use protobuf.

Following is an example of exprotobuf

defmodule Messages do use Protobuf, """ message Msg { required uint32 value = 1; } """ end

In this example the use takes a string parameter in which we define a Msg type in protobuf DSL which has one field i.e. value . When the code runs you have function Messages.Msg.new, Messages.Msg.encode, Messages.Msg.decode which helps you in creating, encoding and decoding your Msg type respectively.

In __using__ macro protobuf parses over the protobuf DSL and generates respective modules and functions.

Go use use

Now you should have a better idea of how use is being used by various libraries and can leverage it in your modules as well to decrease the boilerplate.

Follow @zabirauf