laiboonh
This is a code snippet from the metaprogramming elixir book.
defmacro test(description, do: test_block) do
test_func = String.to_atom(description)
quote do
@tests {unquote(test_func), unquote(description)}
def unquote(test_func)(), do: unquote(test_block)
end
end
Can someone enlighten me on what is def unquote(test_func)(), do: unquote(test_block) doing? How is it even legal syntax??? I tried it out on iex:
iex(67)> defmodule Test do
...(67)> def test(a)(), do: a
...(67)> end
** (CompileError) iex:68: invalid syntax in def test(a)()
iex:68: (module)
Trending in Questions
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
Hello,
I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
So my question is quite simple and i have found no conclusive answer on forum, google or AI.
Should we use :erlang.float for Integer to ...
New
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New
Documentation
While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
Other Trending Topics
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hi there! We created Gust: A task orchestrator inspired by Airflow.
For those who have never heard about Aiflow, it’s a Python-based wor...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
Aludel - LLM Evaluation Workbench
Aludel is an embeddable Phoenix LiveView dashboard for evaluating and comparing LLM prompts across mult...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #ai
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 8- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
h4cc
unquoteis a function to “create code from data” simply said.When this is executed
def unquote(test_func)(), do: unquote(test_block)the result will be
def :description_as_atom(), do: [list, of, test, blocks]which will be valid code for the compiler.
Short:
unquotewill mostly be called in macros to generate code from parameters (which is data at compile time), so only the result ofunquotewill stay afterwards.Eiji
@laiboonh: Inside
quotedo_block your expressions are quoted.For example:
Similarly
test_funcanddescriptionare quoted too.Simple explanation for new developer is that
unquoteconverts quoted expressions (AST) to their “normal” form.For example:
So your line is “translated” from Elixir AST:
to “normal” code like:
You can see how it looks by inspecting variables in
quotedo_block without unquote part.Please see: Quote and unquote for more informations.
laiboonh
Hi, thanks for helping me out here. One thing i don’t understand is what actually happens in
unquote. I have modified your code slightlyLet’s not use AST literals but something else so that we can see the difference.
Example.sample(%{name: "Lai"}). This is my understanding, correct me if i’m wrong.I understand that arguments become quoted expression inside the body of a macro. Hence
abecomes{:%{}, [line: 41], [name: "Lai"]}inside the macro body.unquoteis like string interpolation hence we “substitute” inaand the macro body becomesIO.inspect quote do: {:%{}, [line: 41], [name: "Lai"]}finally when you quote some quoted expression (AST) you get back the same quoted expression and IO.inspect prints out
{:%{}, [line: 41], [name: "Lai"]}Is this how it goes? I am a bit confused by your statement.
{:%{}, [line: 41], [name: "Lai"]}or%{name: "Lai"}benwilson512
Think of
unquoteas similar to#{}in strings. If you havename = "Bob"; greeting = "hello #{name}"the contents ofnameare injected into thegreetingstring producing"hello Bob".When you do something like
you’re inserting the AST contents of
capitalize_astintoresultwhich makesresultthe AST:IO.inspect(unquote(String.capitalize("hello"))laiboonh
Actually i was just curious whether
unquotedoes a substitution or does a conversion as well like Eiji mentioned. I rationalized that its like you said a mere substitution.No matter
unquoteis unquoting an expression or a quoted expression, it will in the end result in an AST becauseunquotehas to happen within aquoteblockEiji
@laiboonh: You can think about AST like a Assembler code.
AST is a data (in tuple notation), but it could be nested instead of simple Assembler plain instructions list.
quoteis changing code to AST, so you are generating quoted code inquoteblock. You cannot access variables outside of this block unless you callunquote.You can think about quoting like about generating file using controller data. Your controller data are all variables inside your macro/function including it’s arguments. To access them instead of calling
<%= assigns.something %>you are usingunquote(something).unquotefetches raw value of variable and/or expression and puts it into quote block.Finally
quotewill return quoted code block and Elixir compiler will generate “normal” code (normal - I mean that code you can see - without AST) - it’s expanding instructions to real code.About your code:
both of them returns unquoted raw value of that expression.
What unquote is doing is like undo of one quote call and evaluate it putting into quoted expression.
When you are working for example with lists in recursive method like:
you need to implement also case when
do_somethingis called with empty list like:Similarly unquote works with raw values. You have quoted variable/expression
ntimes. unquote is doingundofor first (top)quote, but when it’s called with raw value then it just returns that value and finally in both cases it evaluates it.So:
Note: I used here raw value (5) that’s already unquoted.
OvermindDL1
Eh, not really like assembler, it is the very definition of AST. Elixir’s AST.
The compilation process goes: Elixir → Elixir’s AST (what
quotegives you) → Erlang (Abstract Format, basically it’s AST) → Core Erlang → BEAMWith a variety of translators along the way too.
Basically take this Elixir:
To this Elixir AST:
To this Erlang:
To this Core Erlang:
To this BEAM Assembly:
And that is what is loaded by the VM.
laiboonh
Nice code there to challenge one’s understanding of unquote but i think its more illustrative if we used something that is not an AST Literal