Alex Antonov
Alex Antonov

Reputation: 15156

Why can't I put map correctly as argument in elixir?

I'm playing with use functionality in elixir. I can't understand one thing:

defmodule Alex do
  use Included,
    names: [:helen, :rebekka],
    states: [
      %{
        :name => :start
      }, [
        name: :finish
      ]
end

I placed different constructors (map & keyword) just to show the difference. I have a simple elixir module which returns me a values:

defmodule Included do
  demacro __using__(opts) do
    IO.puts Keyword.get(opts, :names) # => [:helen, :rebekka]
    IO.puts Keyword.get(:states) # => [{:%{}, [line: 8], [name: :start]}, [name: :finish]]
  end
end

Why do I receive this strange map and how can I get normal maps in my module?

Upvotes: 2

Views: 344

Answers (1)

Patrick Oscity
Patrick Oscity

Reputation: 54684

What you get is the AST representation of the opts, just like any arguments that are passed to macros. If you are using proplists, these happen to take the same form in quoted an unquoted form:

iex> [name: :finish]
[name: :finish]

iex> quote do: [name: :finish]
[name: :finish]

Maps however don't, because they are not among the basic data types:

iex> %{name: :finish}
%{name: :finish}

iex> quote do: %{name: :finish}
{:%{}, [], [name: :finish]}

This is the reason why proplists are the preferred way to pass options to a macro. However, you can use an unquoted map within a quote as expected:

defmodule Included do
  defmacro __using__(opts) do
    quote do
      IO.inspect unquote(opts)
    end
  end
end

defmodule Alex do
  use Included, %{name: :start}
end

This will simply print

%{name: :start}

Upvotes: 2

Related Questions