I am trieing to understand the julia macros, but I just can’t understand when do I have to use esc, quote, $, eval or so…
Can someone give me the easiest tutorial I can understand? How do you know when to use what?
It would be really nice to have an easier explaination of every command there, to catch the flow.
Heres a short overview.
Note: I wrote this on my phone and haven’t been able to test it so there may be some bugs in the sample code.
Use it for constructing blocks of code.
edit: added missing
Splices in code
macro double_input(fn, x)
# If x is an expression with side effects like `print(b)`
# we don't want to do that twice so we assign it to `z` first.
z = $(x)
@double_input div 3
# returns 1
Use it for variables assigned to in macros that you want visible externally
macro setvar(x, y)
$(esc(x)) = $(y)
Allows you to splice in code without interpolating it.
Shouldn’t be used in macros or functions for the most part. It can be however useful to use at top level if you have a large number of similar functions to define.
for op in [:(+), :(-), :(*), :(/)]
@eval Base.$(op)(x::MyType, y::MyType) = MyType($(op)(x.x, y.x))
Wow guys, these personal macro tutorials and workshop are awesome!
I also have a couple of tutorials:
The video is from 2016 so some syntax has changed, but most of the metaprogramming section is still valid.
This particular example does not work:
ERROR: syntax: field name "Main.field1" is not a symbol around REPL:1
 top-level scope at REPL:1
I was using
eval for something similar, but it seems that if a macro could be used for that, it would be better. What is the best way to share fields between structs?
I’d encourage you to read about macro hygeine to see what’s going on here:
julia> macro shared_fields()
ex = quote
@shared_fields (macro with 1 method)
julia> struct astruct
(:field1, :field2, :field3)
@macroexpand is also quite useful for debugging these things:
julia> macro shared_fields1()
@shared_fields1 (macro with 1 method)
julia> macro shared_fields2()
end |> esc
@shared_fields2 (macro with 1 method)
julia> @macroexpand @shared_fields1
#= REPL:3 =#
#= REPL:4 =#
julia> @macroexpand @shared_fields2
#= REPL:3 =#
#= REPL:4 =#
Yep, it was missing an
esc I have gone back and updated the example and added a note that it was edited.
I just realized there was actually a mistake in that section of the documentation that I linked to so I edited my comment to use the 1.6-dev docs that have fixed the mistake. @lmiq , you may want to use the updated link so it makes more sense.
I think these contents are actually very useful for anyone who wants to understand the julia macros.
Don’t you guys think we should collect the resources at the end of the https://docs.julialang.org/en/v1/manual/metaprogramming/ ?
And by time someone will definitely group these information and provide some extension to the understanding of the topic?
I thought many times that we should have a “Julia by examples” docs, built from community experiences. To be sincere, I have read many times the docs as they are, for example this metaprogramming section, and I have a hard time understanding what those things are for. I am not a computer scientist, and most times I only get the idea of what the experts are trying to explain after seeing a few examples of the functions in different contexts. After I understand how things work, when I read the docs again, I find that they are most of the time perfectly written, but a dedicated docs only for examples would be a great addition. This is how we do for plots, isn’t it?
On the other hand, perhaps the search history of this same discourse is going to achieve that goal.
I think the manual, and particularly that section, would benefit a lot from more examples, practical tips, common use cases, pitfalls.
Incremental additions are great, but I hope one of these days someone knowledgeable about Julia’s metaprogramming will sit down and do a major rewrite. I used Common Lisp macros extensively for years, but I still think of Julia’s macros as a minefield.