amalbuquerque

amalbuquerque

Clear definition of unquote fragments

Hi there,

After reading @ericmj response here (Using unquote outside of quote block - #6 by ericmj) about “unquote fragments”, I still can’t completely grasp the concept.

I’ve read the documentation many times now, besides some other resources (including McCord’s Metaprogramming Elixir), and I can’t reach to a concrete definition of what an unquote fragment is.

I’ve read in some places that “unquote fragments” is the usage of unquote that lets us dynamically define functions and nested macros (The minimum knowledge you need to start Metaprogramming in Elixir - DockYard). After reading all this, I think both unquote/1 calls on the documentation example are “unquote fragments”, since they will be injected on the caller context and won’t have an explicit quote block enclosing them. Am I right?:

    defmacro defkv(kv) do
      quote bind_quoted: [kv: kv] do
        Enum.each kv, fn {k, v} ->
          def unquote(k)(), do: unquote(v)
        end
      end
    end

And consider this example please:

defmodule Foo do
  alias Baz

  fun_definition = {:bar, [], [{:arg, [], nil}]}
  body = {:__block__, [], [{:*, [], [{:arg, [], nil}, {:arg, [], nil}]}]}
  function = :bar
  arity = 1

  def(unquote(fun_definition)) do
    mfa = Baz.mfa(__MODULE__, unquote(function), unquote(arity)) # returns "Module.function/arity"
    Baz.run(mfa, fn -> unquote(body) end)
  end
end

Here I think the unquote(fun_definition) is definitely an unquote fragment because is allowing us to dynamically define the function. But I am not so sure regarding the other unquote/1 calls for function, arity and body. Since they are contributing for the dynamic definition of the function body, are they also unquote fragments?

Thanks in advance,
And thank you all for the amazing community!
lejboua

P.S.: Given the different opinions and definitions I’ve read, IMO the documentation could be updated to include an explicit unquote fragment definition. This way those like me who are starting to look at Elixir would be able to clearly distinguish between a “normal” unquote inside an explicit quote block and an unquote fragment.

P.S.2: I know that we can use the unquote/1 calls inside the def/2 macro arguments because the def/2 arguments, like any macro, are being quoted for us.

Many thanks!

Most Liked

mudasobwa

mudasobwa

Creator of Cure

That’s how quote/2 works, it simply quotes terms without further digging in. Maybe the example with unquote: false would shed some light.

iex|🌢|1 ▶ quote unquote: false, do: unquote(:foo)
{:unquote, [], [:foo]}
iex|🌢|2 ▶ quote unquote: false, do: unquote(:foo)()
{{:unquote, [], [:foo]}, [], []}

So the former results in :foo and the latter results in the plain AST triple with :foo coming from unquote(:foo) and the rest coming from parentheses. It’s like

iex|🌢|3 ▶ quote do: :foo + 42
{:+, [context: Elixir, imports: [{1, Kernel}, {2, Kernel}]], [:foo, 42]}

where :+ is the top-level AST term; () become a top-level AST term in your last example, but parentheses are a special case and they are becoming {:foo, [] = _meta, [] = _args} instead of literally the same {:(), [] = _meta, [:foo]}. :() notation is not possible because args might be not empty. Technically, it might have been {:(), [], [:foo, []]}, but it would make is harder to walk through.

kip

kip

ex_cldr Core Team

I think this post has a good summary: Using unquote outside of quote block

amalbuquerque

amalbuquerque

Hi @kip, thanks for the reply. I’ve mentioned that post on my initial message. I understand why we can do it, it may seem at first glance there’s no quote block wrapping the unquote call, but there is one in fact due to the macro arguments being quoted for us.

What I didn’t understand and think it isn’t completely clear on the documentation is the concept of unquote fragment. Saying that it is what we use to dynamically define a function IMO gives room for interpretation.

Where Next?

Popular in Questions Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lists...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

Other popular topics Top

Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36432 110
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement