# Metaprogramming: macro calling another macro making named variables

**URL:** <https://discourse.julialang.org/t/metaprogramming-macro-calling-another-macro-making-named-variables/109621>\
**Category:** General Usage\
**Tags:** question, metaprogramming\
**Created:** [February 2, 2024, 1:58pm UTC](https://discourse.julialang.org/t/metaprogramming-macro-calling-another-macro-making-named-variables/109621 "2024-02-02T13:58:44Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [February 2, 2024, 1:58pm UTC](https://discourse.julialang.org/t/metaprogramming-macro-calling-another-macro-making-named-variables/109621/1 "2024-02-02T13:58:45Z")

</div>

Ooof, I need some metaprogramming help… There is the macro `@parameters x = 0.5`. The macro, in a simplified sense, does the following: makes a named parameter with name `:x` and default value `0.5` and returns the container as a custom type `Num(:x, 0.5)` and assigns this to the variable `x`. I want to make a new macro `@named_parameters vars...` to be called like e.g., `@named_parameters x y ` which would apply the `@paramaters` macro above to two existing variables `x, y` with real values. It would make two `Num(:x, x)` and `Num(:y, y)` and assign that to `x, y`, using `@parameters`.

Here is what I have, but it is not correct:

```julia
using ModelingToolkit: @parameters

macro named_parameters(vars...)
    expr = Expr(:macrocall, Symbol("@parameters"))
    for v in vars
        push!(expr.args, :($(QuoteNode(v)) = $(esc(v))))
    end
    return expr
end

A = 0.5
B = 0.5
@named_parameters A B # should make the parameters

```

what would be the “correct way” to do this, if any?

For reference `@parameters` comes from ModelingToolkit.jl and can be called with multiple parameters as

```julia
@parameters begin
   A = 0.3
   B = 0.2
end

```

which is what inspired the `for` loop in my macro version.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [February 2, 2024, 2:04pm UTC](https://discourse.julialang.org/t/metaprogramming-macro-calling-another-macro-making-named-variables/109621/2 "2024-02-02T14:04:51Z")

</div>

```julia
x = :A
y = :B
@parameters $x $y

```

and use loops, etc. The interpolation works into it, so you don’t need to metaprogram around it.

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [February 2, 2024, 2:08pm UTC](https://discourse.julialang.org/t/metaprogramming-macro-calling-another-macro-making-named-variables/109621/3 "2024-02-02T14:08:16Z")

</div>

That’s not what I want. I want

```julia
A = 0.5 # notice its a real number
B = 0.5
@parameters A B # makes parameter A with default value 0.5

```

in my code `A, B` are the keyword arguments to functions that provide the default values to parameters that participate into equations. So making them symbols would require lots of boilerplate code. That’s exactly why I want this macro, so that the _existing expressions_ in my code like

```julia
x ~ A*y - B

```

automatically become “parameterized” as `A, B` are no longer Reals but `Nums` with default values.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [February 2, 2024, 4:16pm UTC](https://discourse.julialang.org/t/metaprogramming-macro-calling-another-macro-making-named-variables/109621/4 "2024-02-02T16:16:50Z")

</div>

> [@Datseris](#):
>
> what would be the “correct way” to do this, if any?

You’ll get better advice if you include the result of `@macroexpand` on what you have now.

I suggest grabbing the code for `@parameters` and modifying it to do what you want. It’s legal to use a macro to build up another macro, but it can produce all sorts of strange edge cases which are tricky to reason about.

It sounds like what you want is a small modification of `@parameters`, the easy way to achieve this is to make small modifications to `@parameters`.

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [February 6, 2024, 9:30am UTC](https://discourse.julialang.org/t/metaprogramming-macro-calling-another-macro-making-named-variables/109621/5 "2024-02-06T09:30:11Z")

</div>

Right, yes. Well, the macroexpand of the macro I want to “re-create” is:

```julia
 @macroexpand @parameters begin
       a = 0.2
       b = 0.2
       end
quote
    a = (ModelingToolkit.toparam)((Symbolics.wrap)((SymbolicUtils.setmetadata)((Symbolics.setdefaultval)((Sym){Real}(:a), 0.2), Symbolics.VariableSource, (:parameters, :a))))
    b = (ModelingToolkit.toparam)((Symbolics.wrap)((SymbolicUtils.setmetadata)((Symbolics.setdefaultval)((Sym){Real}(:b), 0.2), Symbolics.VariableSource, (:parameters, :b))))
    [a, b]
end

```

Inspired by this I thought I would make a loop that pushes expressions and then “quotes” them, like so

```julia
macro named_parameters(vars...)

    return quote
    out = []
    for v in vars
        res = (ModelingToolkit.toparam)((Symbolics.wrap)((Symbolics.SymbolicUtils.setmetadata)((Symbolics.setdefaultval)((Sym){Real}($(QuoteNode(v))), $(esc(v))), Symbolics.VariableSource, (:parameters, $(QuoteNode(v))))))
        push!(out, res)
    end
        $(out...)
    end

end

```

but alas this doesn’t work either irrespecitvely of if I put the loop inside the `quote` or not. When inside the loop it says “`v`” not defined when I run the macro…

---

<div class="post-metadata">

**Author:** ![JonasIsensee](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jonasisensee/32/4704_2.png) [@JonasIsensee](https://discourse.julialang.org/u/JonasIsensee)\
**Post date:** [February 6, 2024, 10:04am UTC](https://discourse.julialang.org/t/metaprogramming-macro-calling-another-macro-making-named-variables/109621/6 "2024-02-06T10:04:42Z")

</div>

Is this approximately what you were looking for?

```julia
macro named_params(vars...)
           expr = Expr(:block)
           for var in vars
               binding = esc(var)
               varname = QuoteNode(var)
               push!(expr.args, 
                   :($binding = (; name=$varname, val=$binding) )
                   )
           end
           push!(expr.args, Expr(:vect, esc.(vars)...))
           return expr
       end
@named_params (macro with 1 method)

julia> @macroexpand @named_params A B
quote
    A = (; name = :A, val = A)
    B = (; name = :B, val = B)
    [A, B]
end

julia> function testfun(; a=1, b=2, c=3)
           @named_params a b c
       end
testfun (generic function with 1 method)

julia> testfun()
3-element Vector{@NamedTuple{name::Symbol, val::Int64}}:
 (name = :a, val = 1)
 (name = :b, val = 2)
 (name = :c, val = 3)

```

This is obviously just a demo for using both the name and previously assigned value without actually using the MTK `Num`.

---

<div class="post-metadata">

**Author:** ![jameson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jameson/32/23_2.png) [@jameson](https://discourse.julialang.org/u/jameson)\
**Post date:** [February 6, 2024, 1:17pm UTC](https://discourse.julialang.org/t/metaprogramming-macro-calling-another-macro-making-named-variables/109621/7 "2024-02-06T13:17:57Z")

</div>

macrocall takes a hidden argument, so you are better off generating the initial expression with the parser instead of manually (the splatted initial args list is optional):

`expr = :(@parameters $(args…))`

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [February 20, 2024, 11:17pm UTC](https://discourse.julialang.org/t/metaprogramming-macro-calling-another-macro-making-named-variables/109621/8 "2024-02-20T23:17:24Z")

</div>

omg yes hell yeah thank you so much!!! That is _exactly_ what I Was looking for!!! For reference, the final solution is:

```julia
macro named_params(vars...)
    expr = Expr(:block)
    for var in vars
        binding = esc(var)
        varname = QuoteNode(var)
        push!(expr.args,
            :($binding = (ModelingToolkit.toparam)((Symbolics.wrap)((SymbolicUtils.setmetadata)((Symbolics.setdefaultval)((Sym){Real}($varname), $binding), Symbolics.VariableSource, (:parameters, $varname)))))
            )
    end
    push!(expr.args, Expr(:vect, esc.(vars)...))
    return expr
end

```
