riccardomanfrin

riccardomanfrin

I’m trying to understand how macros and module definitions interact with each others and I’m having few cases which I don’t understand. The below example has some pseudo doctest to show my doubts.

What I need is to support case 5. Thanks for the support in advance

defmodule Foo do
  @doctest """
  Case 1 OK: Trivial (and useless) case.. (Foo.Case1)

      iex> Foo.Case1.foo
      "local stuff"

  Case 2 OK: Injects the Case2 in WrapMod and uses its args
  WARNING: comment Case4 for this to work (head scratching)

      iex> WrapMod.Case2.foo
      [foo: "bar"]

  Case 3 FAILED!!!! Injects used args into the Foo.Case3.foo function

  Error:

    example.ex:24: undefined function args/0 (expected Foo.Case3 to define
    such a function or for it to be imported, but none are available)

  Desiderata:

    iex> Foo.Case3.foo
    [foo: "bar"]

  Case 4 KINDA NOT OK: Super clunky combo of case 2 and 1

  It works, but it HIDES!!!!! Case 2: Call to `WrapMod.Case2.foo` is not available
  anymore

      iex> WrapMod.Case4.foo
      "local stuff"
      iex> WrapMod.Case2.foo
      UndefinedFunctionError

  Case 5 FAILED: Hyper clunky combo of case 2 with case 3 <- which is not working :(

  This is where I'd want to get to: I would like to be able to invoke
  and use the evaluated Foo.Case3.foo from within the quoted  Case5 quoted module code

  """

  defmacro __using__(args) do

    #Case 1
    defmodule Case1 do
      def foo() do
        "local stuff"
      end
    end

    #Case 2
    quote do
      defmodule Case2 do
        def foo() do
          unquote(args)
        end
      end
    end

    #Case 3
    #defmodule Case3 do
    #  def foo() do
    #    quote do
    #      unquote(args)
    #    end
    #  end
    #end

    # Case 4: comment me to get back WrapMod.Case2.foo which is otherwise no more available!!!
    quote do
      defmodule Case4 do
        def foo() do
          Case1.foo()
        end
      end
    end

    #quote do
    #  defmodule Case5 do
    #    def foo() do
    #      Case3.foo()
    #    end
    #  end
    #end

  end
end

defmodule WrapMod do
  use Foo, foo: "bar"
end

For the records, case 3 works if I change it like this:

    #Case 3
    defmodule Case3 do
      def foo() do
        quote do
          var!(args)
        end
      end
    end

but this is giving me

iex(1)> Foo.Case3.foo
{:var!, [context: Foo.Case3, import: Kernel], [{:args, [], Foo.Case3}]}

which is clearly not what I want

Showing Posts 1 to 2

riccardomanfrin

riccardomanfrin OP

I figured how to sort out the reason why Case4 obliterates Case2. Injection through quote expands the AST returned by the __using__ macro. In order to expand both cases, they need to stay together a the end of the __using__ macro and wrapped into a list:

[
   quote do
      defmodule Case2 do
        def foo() do
          unquote(args)
        end
      end
    end,
   quote do
      defmodule Case4 do
        def foo() do
          Case1.foo()
        end
      end
    end
]
fuelen

fuelen

As in regular functions, macro returns the last expression.
It is not necessary to wrap two quote expressions into a list. You can simply wrap both module definitions into 1 quote block:

quote do
  defmodule Case2 do
    def foo() do
      unquote(args)
    end
  end

  defmodule Case4 do
    def foo() do
      Case1.foo()
    end
  end
end
— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
apz
I’m new to elixir and just tried to install the elixirLS extension for VScode(ium) and it is throwing some errors that I would like help ...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews