Weird tuple

Why is that:
quote do: {1, :two, "three"}
{:{}, [], [1, :two, "three"]}

quote do: {1, :two}
{1, :two}

One is an ast the other no.
I probably missed something obvious may be It should be in red in the official tutorial.

Thanks!

This is explained in the documentation for quote - https://hexdocs.pm/elixir/Kernel.SpecialForms.html#quote/2-quote-literals.

3 Likes

Thanks but there was actually no explanation of the why. When you return two similar objects you have two differents outcome.

2-element tuples is represented as is in AST-form :slight_smile:

2 Likes

Two element tuples are represented as literals in AST to allow keyword lists to be literals. It simplifies writing macros tremendously.

1 Like

Do you have an example?
thanks

Let’s take any macro that takes options.

Let’s say you have a macro foo/2 that takes options as the second argument. When called as foo(a, bar: 1, baz: 2),you’ll get {:a, _meta, nil} as the first argument and [{:bar, 1}, {:baz, 2}] as the second. It’s easy to extract options with Keyword.get/3 or whatever - it’s just a keyword list.

If two-element tuples weren’t literals, in this second argument you’ll receive [{:{}, _meta, [:bar, 1]}, {:{}, _meta, [:baz, 2]}]. Extracting the value for the :bar option suddenly becomes problematic.

This would be even more painful, considering that the foo do xyz end syntax is just a syntax sugar for foo([{:do, (xyz)}]), so you’d need to do this dance for every macro that takes a block - and there’s a lot of them.

I also recommend the Syntax Reference page from docs - it lays out all the AST elements and explains how they tie together.

7 Likes

The main thing I don’t like is they lose context information (line number and so forth) due to not being a 3-tuple. I’d honestly prefer if everything in the AST were 3-tuple, after all it’s easy enough to make helper functions to extract what you need, plus those would just be all around easier to process with fewer cases. Though if I were to design it over instead of it being {name, metadata, args} I’d probably do {type, metadata, [name | args]} as then you could wrap things like literals without needing wrapping blocks all over the place, thus unifying their representation as well.

1 Like

I agree with you. Really that s weird and I don t mean to upset people. Why don t they make it all AST? for speed reason? Or macro programming is that important?

They did it for ease of macro programming so I get and understand their reasoning, I just don’t think that making it like that was as important as making it homogeneous in form, even if it meant a few more helpers, but then again I tend to lay on the side of coding for things that are more ‘expected’ than ‘easy’, where ruby tends to lay on the side of ‘easy’ but not always ‘expected’. ^.^;

2 Likes

Your suggestion is closer to what the erlang AST looks like. It does make some things easier and things are very consistent. I don’t quite understand the problem with macros as most (except you? :wink:) use quote and unquote which bypass that problem.

1 Like

I know, it’s closer to how ‘most’ languages do their AST’s. ^.^;

I tend to do a lot of things that are impossible to represent in the Elixir syntax, thus quote/unquote fails (not homoiconic), so I often have to drop down to AST. Plus I do a LOT of matching of AST and it’s easier just to put in the tuples in the functions heads instead of multiple levels of unquote(quote(...)) that prevents me from matching things out of it as well. ^.^;