简体   繁体   中英

Elixir quote/unquote and macros behaviour

I have two versions of __using__ , however, first version has different behaviour from one I've expected. This code does not work properly (actually, it does not import anything).

defmodule SomeModule do
  defmacro __using__(opts \\ []) do
    quote do
      opts = unquote(opts)
      if Keyword.has_key?(opts, :my_key) && opts[:my_key] == 3 do
        import MyModuleOne
      else
        import MyModuleTwo
      end
    end
  end
end

And this is the working version, however, I don't like having two separate quote parts.

defmodule SomeModule do
  defmacro __using__(opts \\ []) do
    if Keyword.has_key?(opts, :my_key) && opts[:my_key] == 3 do
      quote do
        import MyModuleOne
      end
    else
      quote do
        import MyModuleTwo
      end
    end
  end
end

How should the first one be rewritten for it to work properly?

That's a tricky one! Took me a while to work out the reason...

Before going into why, let me assure you that your macro is perfectly valid, and Elixir works precisely as you told it .

I tried to expand the two macros you posted and got the same result, ie the correct thing is being imported. But why does it not work as you expected?

Here is why,

It is important to notice that import/2 is lexical

from the docs for import

and let me show you 2 examples

iex(1)> import Enum, only: [into: 2]
Enum
iex(2)> into [a: 1], %{}
%{a: 1}
iex(3)>

and...

iex(1)> if true do
...(1)>   import Enum, only: [into: 2]
...(1)> end
Enum
iex(2)> into [a: 1], %{}
** (CompileError) iex:2: undefined function into/2

the import only takes effect inside the clause that you wrote it :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM