Already defined as defmacro problem

Hello.
I’m reading the source code of elixir. I tried to change some functions in assertions.ex.

  @doc """
  Asserts `value` is truthy, displaying the given `message` otherwise.

  ## Examples

      assert false, "it will never be true"

  """
  defmacro assert({:=, meta, [left, right]} = assertion, message) do
    code = escape_quoted(:assert, meta, assertion)

    # If the match works, we need to check if the value
    # is not nil nor false. We need to rewrite the if
    # to avoid silly warnings though.
    check =
      suppress_warning(
        quote do
          case right do
            x when x in [nil, false] ->
              raise ExUnit.AssertionError,
                expr: expr,
                message: unquote(message)

            _ ->
              :ok
          end
        end
      )

    __match__(left, right, code, check, __CALLER__)
  end

  def assert(value, message) when is_binary(message) do
    assert(value, message: message)
  end

  def assert(value, opts) when is_list(opts) do
    unless value, do: raise(ExUnit.AssertionError, opts)
    true
  end

With that code, the compiler throws an error.

 make compile                                       
==> ex_unit (compile)

== Compilation error in file lib/ex_unit/assertions.ex ==
** (CompileError) lib/ex_unit/assertions.ex:416: def assert/2 already defined as defmacro in lib/ex_unit/assertions.ex:392
    lib/ex_unit/assertions.ex:416: (module)
make: *** [lib/ex_unit/ebin/Elixir.ExUnit.beam] Error 1

the assert macro has pattern match in its arguments. So I don’t know why the compiler says like this.

def assert/2 already defined as defmacro in lib/ex_unit/assertions.ex:392
    lib/ex_unit/assertions.ex:416: (module)

Elixir has a single namespace so functions and macros need to have different names from each other otherwise, as you see, you are trying to re-use a name that is already defining a function (with def) as a macro (using defmacro)

2 Likes

Thank you.