Is there an attempt by the compiler to compile the first AST before AST expansion?

I understand that the compilation process (simplified) is something like:

source codeInitial ParsingASTExpansionexpanded ASTBytecode Generationbytecode

I am curious is there an attempt by the compiler to compile the first AST before proceeding to expansion. I am making this guess based on the observation is make from the below code.

This does not compile with error: undefined function hello/1 when i expected it to; as after AST expansion function hello would have been there for invocation already.

defmodule Foo do
  defmacro my_macro() do
    quote do
      def hello(person) do
        IO.inspect person
      end
    end
  end
end

defmodule Bar do
  require Foo
  Foo.my_macro()
  hello("Bob")
end

But this does

defmodule Foo do
  defmacro my_macro() do
    quote do
      def hello(person) do
        IO.inspect person
      end
    end
  end
end

defmodule Bar do
  require Foo
  Foo.my_macro()
  def run() do
    hello("Bob")
  end
end

Well, a function does only exist, after the end of defmodule! So you can’t use it before the module is completely defined. Doing your first example without a macro, but defining that function by hand doesn’t work either:

defmoduie Foo do
  def hello(name), do: name
  hello("Foo")
end

Will result in a undefined function hello/1 as well.

3 Likes

Only whole modules are compiled. In order to call a function, it needs to be compiled. But in the setup you showed, in order to compile the module, you need to call the function. So it creates a circular dependency on needing to call the function in order to compile it. That’s why it fails.

When it’s inside other function, it will be called only when the module is completely compiled, so that is perfectly fine.

4 Likes

Thank you all for answering my newbie questions :slight_smile: