In the context of iex…
…yields no error
IO.inspect :a do
5
end
#==> :a
…yields an error
:a do
5
end
error: syntax error before do
This question is in regards to the treatment of blocks in elixir, as I am trying to understand when they are automatically converted into kwlists.
They’re always converted to kw lists in contexts that allow kw lists. You can’t pass a kw list to the atom :a
– it’s a syntax error.
For perhaps more clarity, the first example is equivalent to both of the following:
IO.inspect(:a, do: 5)
IO.inspect(:a, [{:do, 5}])
The :do is being passed as an option to the inspect function (and then ignored).
2 Likes
That cleared up everything, especially the added clarification. Which explains why the block was ignored (not outputted) by the inspect.
Just to clarify, the macro tag is because I wanted to know if this conversion takes place even when internal representation is taking precedent (such as when passed as an arg to a macro), but this seems to happen before all that.
1 Like
Here’s a handy guide on syntax sugar: Optional syntax sheet — Elixir v1.16.2
It’s definitely worth understanding. There’s surprisingly little of it!
4 Likes
Thanks, was looking for something like this, but was searching under “blocks”.
More appreciation for the way the core team achieved elegance in elixir’s syntax.
1 Like
It also might be useful to think of it in “reverse” as it’s a little more accurate: The do
syntax is actually sugar. It’s really more: “when can do
stand in for a :do
key in a kwlist” if that makes sense. The “truer” syntax—for lack of a better word—is def foo, do: "foo"
, or rather def foo, [{:do, "foo"}]
.
I actually have a bit of trouble myself grokking how the def
family of macros work because otherwise Elixir is really very lispish—it’s just keyword lists all the way down.
defmodule(Foo, [{:do, def(bar, [{:do, "foo"}])}])
1 Like
One thing I didn’t understand in the example from the guide was
defmodule Math do
def add(a, b) do
a + b
end
end
turns into
defmodule(Math, [
{:do, def(add(a, b), [{:do, a + b}])}
])
What happens with add(a, b), but since you said def is a macro this would be because add(a, b) does not get evaluated, but rather literally inserted into some internal representation code fragment?
Yes, but I never fully understood how they work the parens.
If you really wanna bend your brain, see here.
Here be dragons.
This can’t be the initial definition though?
Is this due to elixir being homoiconic?
I honestly don’t know! I haven’t never taken the time to fully understand at this level. defmacro defmacro
calls define(:defmacro, ...)
so AFAIK it’s the initial definition, at least in the Elixir part of Elixir’s source. Clearly there is something in the Erlang bits that are making that possible.
1 Like
Ah just as I thought. Seems like macros are actually just quotes and unquotes but with some default behaviour with respect to having at least on unquote at the end of the macro.
I don’t know the details but, I just cursory view at defp define, and it seems like quote and unquote may be closer to the Erlang side of the implementation than defmacro itself.
Thanks for your answers.