riccardomanfrin

riccardomanfrin

Quote, defmacro and modules

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

Most Liked

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

Where Next?

Popular in Questions Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
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
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
idi527
I’ve been re-reading swift book again and noticed that multiline strings there don’t have a trailing line break, unlike in elixir iex(2)...
New

Other popular topics Top

peerreynders
Manning 2016 Halloween weekend sale via Deal of the Day Friday, October 28 - Half off all MEAPs - code WM102816LT Saturday, October 29 ...
326 29600 154
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 45766 226
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
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
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement