Why Code.string_to_quoted optimize do block expression like single line do keyword

Hi,

This is my first thread on the Elixir Forum. :). I try to implement code folding by using Elixir AST. I found weired result after get it from Code.string_to_quoted/1. When we writing code like this:

defmodule A do
  def hello() do
    :world
  end
end

Or

defmodule A do
  def hello(), do: :world
end

Those 2 examples would produce AST result like this:

{:defmodule, [line: 1],
   [
     {:__aliases__, [line: 1], [:A]},
     [do: {:def, [line: 2], [{:hello, [line: 2], []}, [do: :world]]}]
   ]}

But the documentation in SpecialForms.__block__/1 said:

This is the special form used whenever we have a block of expressions in Elixir. This special form is private and should not be invoked directly:

So I guess the first code example should produce like:

  {:defmodule, [line: 1],
   [
     {:__aliases__, [line: 1], [:A]},
     [
       do: {:def, [line: 2],
        [{:hello, [line: 2], []}, [do: {:__block__, [], [:world]}]]}
     ]
   ]}}

If I’m understand correctly. Elixir optimize and produce AST result for the code that has only 1 expression in do block expression?

I guess because your block is only a single expression it is conceptually the same as the expression itself since the return value of a block is its last expression.

This is also true for the block defining the module: you have a single call to def so you get do: {:def ... but if you were defining several functions you would have a __block__ here too.

1 Like

Yep, you understand correctly. Both do: and a single-expression do...end only produce one expression, and so are not wrapped in a block in quoted form.

If you are metaprogramming and don’t want to have to keep this in mind, you can notice when the quoted value of :do in your macro is not a block, and wrap it yourself.

1 Like