svilen

svilen

Author of Concurrent Data Processing in Elixir

Dynamically add module functions in __using__ macro

I have a bunch of functions in a module, that I’d like to dynamically add to a __using__ macro:

defmodule A do
  defmacro __using__(_opts) do
    quote do
      # Dynamically add 
      # def foo(), do: "Foo"
      # and any other functions.
    end
  end

  def foo(), do: "Foo"
end

My goal is to have the functions accessible on the original module, inject them into the module that’s using it via use and make them overridable:

I’m just starting with metaprogramming so I’d appreciate any solutions or pointers in the right direction. Thanks!

Marked As Solved

kip

kip

ex_cldr Core Team

If basically you want to delegate a bunch of functions to another module, have them available as public functions on the new module and also make them overridable then perhaps the following would work? Its not considered good practise to do defining lots of functions in a quote block.

defmodule A do
  defmacro __using__(_opts) do
    quote do
      defdelegate foo(), to: A
      
      defoverridable [foo: 0]
    end
  end
  
  def foo(), do: "Foo"
end

defmodule B do
  use A
end

Also Liked

jswny

jswny

I’m pretty sure you can just import the parent module of the __using__ macro with import A inside the macro. For example, the Phoenix 1.3 generators create the following DataCase module:

defmodule MyApp.DataCase do

  using do
    quote do
      ...

      import MyApp.DataCase
    end
  end

  def errors_on(changeset) ...
end

So, all of the MyApp.DataCase functions will be auto imported into the scope of any module which calls use MyApp.DataCase.

idi527

idi527

Kernel — Elixir v1.20.2 has an example similar to what you want:

defmodule A do
  defmacro __using__(_opts) do
    quote do
      def foo, do: "Foo"

      defoverridable [foo: 0]
    end
  end
end

defmodule B do
  use A

  def foo do
    super() <> "Bar"
  end
end

And then in the shell

iex(1)> B.foo()
"FooBar"
kip

kip

ex_cldr Core Team

import makes the functions from A available in module B but it doesn’t re-export them. Therefore functions in B can invoke the imported functions from A but you can’t call them from outside B. Its nothing to do with use, its how import works.

Overall, your last example isn’t a strong justification for use. Just import would be preferred because the intent is clearer. But I recognise your use case if presumably more complex that just import.

Last Post!

svilen

svilen

Author of Concurrent Data Processing in Elixir

@kip @LostKobrakai Yep, I definitely don’t disagree with you and import is much simpler and clearer for the majority of cases. I was purely interested in how could this be achieved from a metaprogramming standpoint. Whether this is a good or bad idea is a different topic, which I don’t intend to start :slight_smile:

Where Next?

Popular in Questions Top

joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
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
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
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
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
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New

We're in Beta

About us Mission Statement