laiboonh
defmodule Control do
defmacro my_if(expr, do: if_block, else: else_block) do
quote do
Control.do_my_if(unquote(expr), do: unquote(if_block), else: unquote(else_block))
end
end
defmacro my_if(expr, do: if_block) do
quote do
Control.do_my_if(unquote(expr), do: unquote(if_block), else: nil)
end
end
def do_my_if(expr, do: if_block, else: else_block) do
case (expr) do
result when result in [false, nil] -> else_block
_ -> if_block
end
end
end
iex(1)> c "control.exs"
[Control]
iex(2)> require Control
Control
iex(3)> Control.my_if(2==2, do: "true", else: "false")
"true"
What i don’t like about my implementation is that i would like to keep do_my_if as private function but this doesn’t compile if i do that.
I also don’t like the fact that i have to call Control.do_my_if in the macro body, why can’t i simply do do_my_if. During the AST expansion phase do_my_if should be totally legal shouldn’t it?
I looked at the Elixir source code elixir/lib/elixir/lib/kernel.ex at 5feec03db6a134371d9c0f60cc8873232659005e · elixir-lang/elixir · GitHub and the two points i mentioned seemed achievable. I don’t know what i am doing wrong. Any help is appreciated, thanks in advance.
Trending in Questions
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
Documentation
While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
Hello,
I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind.
However, when I launch mix phx.server, I get an error...
New
Hi everyone,
I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding.
I sta...
New
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
I’m working on a small exercise involving update_in/3, and I came up with this solution:
data = %{
name: "Periodic Table",
category:...
New
I’ve got trouble wrapping my head around the order in which functions are called in this snippet (from Phoenix’s authentication):
toke...
New
Other Trending Topics
Edit: 2026 May 15 - This post is archived.
Mob is alive!!
Main docs: mob v0.7.11 — Documentation
A bit of explanation for the slightly c...
New
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hobbes is a low-level distributed database for the Elixir programming language.
Hobbes provides a simple, safe, and scalable storage lay...
New
Hi everyone!
The first release candidate for the Expert language server project is now available!
We’ve published a press release detai...
New
A little off-topic, but I feel like people here have a good head on their shoulders.
I used to be quite good at making software. Was luc...
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
- #ai
- #ecto-query
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #elixirconf-eu
- #api
- #forms
- #metaprogramming
- #hex










Showing Posts 1 to 6- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
OvermindDL1
Your macro’s are calling
do_my_ifin the ‘callers’ scope, not the macro scope. This is proven by showing that both branches are taken:You can change it to (and should, you cannot make it private because anything a defmacro calls (actually calls, not inside a
quote) needs to be publicly accessible, I’m not sure why but they do) by changing your module to be:Which then results in:
I can detail ‘why’ if curious, but looking over the code and getting it to ‘click’ yourself can often be more enlightening in the tough world of macros.
laiboonh
Wow i have much to learn, am i right to say that
unquoteevaluates the expression it is “unquoting” and inserts the result in the expanded AST. Hence my original implementation leads towhen running your example usage
NobbZ
unquotedoes not execute anything.But, lets try to expanding your macro by hand. Perhaps we can enlighten you that way!
Your intitial version:
In the wollowing steps, I wont use the AST, but the human readable representation of the AST to simplify things a bit.
And now lets expand
Controlö.my_if(false, do: IO.inpsect true, then: IO.inspect false:First lets fill in the gaps of the Macro:
Now lets do the unquote:
As you can see, we have finished expanding and compiling the macro. We have left a plain function call in the BEAM-byte code. Its arguments will be evaluated at runtime.
Now lets try the version of @OvermindDL1 which I won’t paste again, using the same snippet as above:
The first thing to mention is, that there is no
quotein the macro definition, therefore the function is called at compile time! In that function is aquote, therefore wi will look at that now:And now unquote this:
As you can see, this version expands into a
case-expression and not a function call. Also sincedo_my_ifis called from insideControlduring compiletime (not from another module during runtime as in your version), you should be able to evendefpit in Overminds version.Somewhere burried in the
Macromodule, there was a function or macro which was able to print the expanded sourcecode of a macro-call. That is very nice when debugging them.OvermindDL1
Yep, NobbZ said it wonderfully!
Macro.expand_once(orMacro.expandto expand all steps) along with I think it wasMacro.to_stringor something like that.s/unquote//NobbZ
That never happened
laiboonh
Thanks guys for helping my out with this. It’s really helpful to know how to expand on the macros by hand. As an extension to this “lesson”, may i verify my understanding using a streamlined version example below:
It will be very very helpful if you can go through again by hand how this whole chain of a more streamlined example got expanded or evaluated. I understand it to be that during “AST expansion phase”, the body of
call_go_macrowill be expanded intodo_go(1)which ultimately expands to the AST ofIO.inspect unquote(1). Then during the final “compilation to bytecode” phase that AST is compile to bytecode and whenevercall_go_macrois called upon,IO.inspect(1)'s bytecode representation is executed during runtime