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
Hello!
Suppose you are building workflow (order / task / payment) processing system with the following requirements:
Each workflow con...
New
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app?
Looking for hints regarding:
Addi...
New
Kia ora,
We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
Hi all, I wanted to ask how the community is dealing with post-release steps.
Today we have Ecto migrations, which make sure that the db...
New
Hello,
I have an Elixir backend that implements a custom protocol over TCP. I want to load test the backend and assess the performance o...
New
Other Trending Topics
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
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve.
They are GUI (Emerge) and State management (S...
New
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










Showing Posts 1 to 6- Show Best Posts
- Show All Posts (oldest first)
- Show All Posts (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