# How best to write this macro?

**URL:** <https://discourse.julialang.org/t/how-best-to-write-this-macro/47817>\
**Category:** General Usage\
**Tags:** metaprogramming\
**Created:** [October 5, 2020, 11:45pm UTC](https://discourse.julialang.org/t/how-best-to-write-this-macro/47817 "2020-10-05T23:45:45Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Joris\_Pinkse](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joris_pinkse/32/216398_2.png) [@Joris\_Pinkse](https://discourse.julialang.org/u/Joris_Pinkse)\
**Post date:** [October 5, 2020, 11:45pm UTC](https://discourse.julialang.org/t/how-best-to-write-this-macro/47817/1 "2020-10-05T23:45:45Z")

</div>

I’m learning about meta programming and as practice, I tried to define a macro that would batch define and initialize arrays of a certain type. I got some of the way, but it’s clunky. What would be a better way of writing this macro that would work for the second call, also, without replacing n with $n? (I know that there are better ways of initializing a bunch of arrays, but that won’t help me learn about macros).

```julia
macro zeros( tp, list... )
  str = ""
	for el in list
      els = split(strip(string(el),['(',')']), [','])
      str *= string( strip(els[1]),"= zeros($tp," )
      for j = 2:length(els) str *= strip(els[j]) * ( j<length(els) ? "," : ");" ) end
  end
  eval(Meta.parse(str))
end

function ugh()
    @zeros Float64 (x,10,3) (y,4)
    n = 10
    @zeros Int64 (x,n,3) (y,4)
end

ugh()

```

---

<div class="post-metadata">

**Author:** ![Amin\_Yahyaabadi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amin_yahyaabadi/32/9826_2.png) [@Amin\_Yahyaabadi](https://discourse.julialang.org/u/Amin_Yahyaabadi)\
**Post date:** [October 5, 2020, 11:55pm UTC](https://discourse.julialang.org/t/how-best-to-write-this-macro/47817/2 "2020-10-05T23:55:11Z")

</div>

If you are using this as a learning platform, it is OK, but I don’t see the reason for using a macro.

```julia
function zeros_batch(type, args)
    for arg in args
        zeros(type, arg...)
    end
end

zeros_batch(Float64, [[10, 3], [4]])

```

You should avoid making the expression using strings (unless there is no other way). You need to use `Expr`, `quote end`, etc for making your expressions.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [October 5, 2020, 11:57pm UTC](https://discourse.julialang.org/t/how-best-to-write-this-macro/47817/3 "2020-10-05T23:57:06Z")

</div>

Is there a reason you’re trying to do this with strings? I would _strongly_ recommend taking advantage of Julia’s built in code representation, `Expr`. Furthermore, you should almost **never** need to use `eval` within a macro.

I think you would benefit a lot from reading [Metaprogramming · The Julia Language](https://docs.julialang.org/en/v1/manual/metaprogramming/index.html) which I think is an excellent introduction to julia metaprogramming.

---

<div class="post-metadata">

**Author:** ![Joris\_Pinkse](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joris_pinkse/32/216398_2.png) [@Joris\_Pinkse](https://discourse.julialang.org/u/Joris_Pinkse)\
**Post date:** [October 5, 2020, 11:58pm UTC](https://discourse.julialang.org/t/how-best-to-write-this-macro/47817/4 "2020-10-05T23:58:45Z")

</div>

Thanks @Mason. I did read that and I agree that it’s an excellent introduction, but clearly not enough for me.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [October 6, 2020, 12:07am UTC](https://discourse.julialang.org/t/how-best-to-write-this-macro/47817/5 "2020-10-06T00:07:30Z")

</div>

Ah, I see, I can try and wrangle up a few more references to send you if you would like!

In the meantime, here is how I would write your macro:

```julia
macro zeros(tp, list...)
    defs = map(list) do ex
        @assert ex.head == :tuple
        name = ex.args[1]
        size = ex.args[2:end]
        :($name = $zeros($tp, $name, $(size...)))
    end
    esc(Expr(:block, defs...))
end

```

We can look at the code it expands to with `@macroexpand` to make sure it does what we want:

```julia
julia> @macroexpand @zeros Float64 (x, 10, 3) (y,4)
quote
    x = (zeros)(Float64, x, 10, 3)
    y = (zeros)(Float64, y, 4)
end

```

---

<div class="post-metadata">

**Author:** ![Joris\_Pinkse](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joris_pinkse/32/216398_2.png) [@Joris\_Pinkse](https://discourse.julialang.org/u/Joris_Pinkse)\
**Post date:** [October 6, 2020, 12:08am UTC](https://discourse.julialang.org/t/how-best-to-write-this-macro/47817/6 "2020-10-06T00:08:57Z")

</div>

That would be awesome, thanks!

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [October 6, 2020, 12:19am UTC](https://discourse.julialang.org/t/how-best-to-write-this-macro/47817/7 "2020-10-06T00:19:45Z")

</div>

A bit of explanation, `list` is going to be `Tuple` of expressions which I expect are of the form `:((name, size...))`, so I am going to `map` over that tuple to turn it into the desired form.

The function `map(f, v)` takes a function `f` and applies it to each element of a container `v` and returns the result, e.g.

```julia
julia> map(x -> x + 1, 1:4)
4-element Array{Int64,1}:
 2
 3
 4
 5

```

The syntax

```julia
map(v) do x
    #= stuff here =#
end

```

is just a fancy way to write

```julia
map(x -> #= stuff here =#, v)

```

so,

```julia
julia> map(1:4) do x
           x + 1
       end
4-element Array{Int64,1}:
 2
 3
 4
 5

```

Alright, so now we see what I’m doing when I write

```julia
    defs = map(list) do ex
        @assert ex.head == :tuple
        name = ex.args[1]
        size = ex.args[2:end]
        :($name = $zeros($tp, $name, $(size...)))
    end

```

This is mapping over `list`, asserting that each element of that list is an expression whose `head` is `:tuple` (i.e. it’s something of the form `:((x, y, z))`), and then taking out the first element of that tuple and saying that’s going to be our variable name, and the rest will say how big our array should be. With those pulled out, I create a new expression that `:($name = $zeros($tp, $name, $(size...)))` where I have interpolated in the variables `name`, `tp` and `size` into a expression an array definition to `name`. I also interpolated in the function `zeros` to ensure that the function _I_ call `zeros` gets used, not whatever some other user might have bound to `zeros`.

This gives us and array of expressions for array definitions and I then stick them into an `Expr(:block)` which is the construct julia uses for holding multiple expressions together, e.g.

```julia
julia> ex = quote
           1 + 1
           2 + 3
       end
quote
    1 + 1
    2 + 3
end

julia> dump(ex)
Expr
  head: Symbol block
  args: Array{Any}((4,))
    1: Expr
      head: Symbol call
      args: Array{Any}((3,))
        1: Symbol +
        2: Int64 1
        3: Int64 1
    2: Expr
      head: Symbol call
      args: Array{Any}((3,))
        1: Symbol +
        2: Int64 2
        3: Int64 3

```

I then apply `esc` to that function which is related to the macro hygeine stuff in [this section of the docs](https://docs.julialang.org/en/v1/manual/metaprogramming/index.html#Hygiene).

This escaped expression is then returned, not `eval`’d, so that it functions like a normal macro.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [October 6, 2020, 12:21am UTC](https://discourse.julialang.org/t/how-best-to-write-this-macro/47817/8 "2020-10-06T00:21:56Z")

</div>

This [recent discourse thread](https://discourse.julialang.org/t/julia-learning-macros-metaprogramming/45753) has some great resources for learning metaprogramming,

---

<div class="post-metadata">

**Author:** ![Joris\_Pinkse](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/joris_pinkse/32/216398_2.png) [@Joris\_Pinkse](https://discourse.julialang.org/u/Joris_Pinkse)\
**Post date:** [October 6, 2020, 12:27am UTC](https://discourse.julialang.org/t/how-best-to-write-this-macro/47817/9 "2020-10-06T00:27:48Z")

</div>

This is really helpful @Mason. Thanks a bunch!
