# Macros to fill keyword arguments

**URL:** <https://discourse.julialang.org/t/macros-to-fill-keyword-arguments/25454>\
**Category:** General Usage\
**Tags:** macros, kwargs, keyword-arguments\
**Created:** [June 19, 2019, 6:48pm UTC](https://discourse.julialang.org/t/macros-to-fill-keyword-arguments/25454 "2019-06-19T18:48:23Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![dstarerstor](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dstarerstor/32/8958_2.png) [@dstarerstor](https://discourse.julialang.org/u/dstarerstor)\
**Post date:** [June 19, 2019, 6:48pm UTC](https://discourse.julialang.org/t/macros-to-fill-keyword-arguments/25454/1 "2019-06-19T18:48:23Z")

</div>

Hi everyone,

I’m having a difficult time understanding how to properly use macros. I’m trying to make a macro `@passkwargs` that will turn

`foo(; @passkwargs(x,y))` into `foo(; x=x, y=y)`

I’m just starting to work with macros and I figured this would be a useful and relatively easy. Unfortunately I’m having a really difficult time navigating variable scope.

I’ve focused around using the idea that you can pass a Pair(Symbol, Any) as a keyword argument. My first try was this:

```julia-auto
macro passkwargs(args...)
    result = (Pair(i,i) for i in args)
    return :($(result)...)
end

```

But instead of getting the desired result, it gives the symbols as both keywords and values. So I tried to evaluate the second item in the pair

```julia-auto
macro passkwargs(args...)
    result = (Pair(i,eval(i)) for i in args)
    return :($(result)...)
end

```

but of course it evaluates the variable in the global scope, and not the scope of the function for which it is called. I’ve since been trying to figure out how esc() works but for some reason its not clicking - I get the Symbol as the keyword but the Expr is the value.

How do I do this? Any help would be appreciated

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [June 19, 2019, 7:19pm UTC](https://discourse.julialang.org/t/macros-to-fill-keyword-arguments/25454/2 "2019-06-19T19:19:51Z")

</div>

Here’s one solution – the trick is that I think you need `QuoteNode` to make the symbols it receives stay symbols in the output:

```julia
macro p3(args...)
    sym = QuoteNode.(args)
    :( $NamedTuple{($(sym...),)}(($(args...),)) ) |> esc
end

using NamedTupleTools # for this constructor

A = rand(1:9, 3,4)
dims = 1

@macroexpand @p3(dims)

sum(A; @p3(dims)...) # needs the ; and ...

```

If you paste this into the REPL it should work find without the `esc`, but if it were in a module, then it would look for `dims` there, not in your scope, if you left this out. The reason for writing `$NamedTuple` is to put this back in the module’s scope, so that the caller need not have loaded it.

---

<div class="post-metadata">

**Author:** ![dstarerstor](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dstarerstor/32/8958_2.png) [@dstarerstor](https://discourse.julialang.org/u/dstarerstor)\
**Post date:** [June 21, 2019, 4:33pm UTC](https://discourse.julialang.org/t/macros-to-fill-keyword-arguments/25454/3 "2019-06-21T16:33:48Z")

</div>

Thanks to @mcabbott because this solution does work well and put me on the right path. However, I’ve been snooping and found a more optimal solution just in case anyone runs into this post in the future. I discovered the `:kw` symbol, which, when used as the head of an expression designates a keyword pair, which is perfect. The new macro is this:

```julia
macro passkwargs(args...)
    kwargs = [Expr(:kw, arg, arg) for arg in args]
    return esc( :( $(kwargs...) ) )
end

```

The benefit of this solution is it can be used anywhere in the list of arguments and does not need a `;` before it, although doing so is perfectly fine.

edit - apparently this only works for a single kwarg, and I’m trying to figure out why

---

<div class="post-metadata">

**Author:** ![hhaensel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hhaensel/32/1207_2.png) [@hhaensel](https://discourse.julialang.org/u/hhaensel)\
**Post date:** [March 23, 2024, 10:17pm UTC](https://discourse.julialang.org/t/macros-to-fill-keyword-arguments/25454/4 "2024-03-23T22:17:53Z")

</div>

Could anyone repeat this solution?  
It would be so nice if this worked out, but I receive an error as soon as I pass more than one argument.

```julia
julia> macro passkwargs(args...)
           kwargs = [Expr(:kw, arg, arg) for arg in args]
           return esc( :( $(kwargs...) ) )
       end

julia> f(args...; kwargs...) = println(args, "\n", Dict(kwargs))
f (generic function with 1 method)

julia> x = 1; y = 2

julia> f(@passkwargs(x))
()
Dict(:x => 1)

julia> f(@passkwargs(y))
()
Dict(:y => 2)

julia> f(@passkwargs(x, y))
ERROR: MethodError: no method matching esc(::Expr, ::Expr)

```

---

<div class="post-metadata">

**Author:** ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)\
**Post date:** [March 24, 2024, 3:13am UTC](https://discourse.julialang.org/t/macros-to-fill-keyword-arguments/25454/5 "2024-03-24T03:13:08Z")

</div>

You don’t need a macro for this anymore. Just call the function as `f(; x, y)`.

```julia
julia> f(args...; kwargs...) = println(args, "\n", Dict(kwargs));

julia> x = 1; y = 2;

julia> f(; x)
()
Dict(:x => 1)

julia> f(; y)
()
Dict(:y => 2)

julia> f(; x, y)
()
Dict(:y => 2, :x => 1)

```

---

<div class="post-metadata">

**Author:** ![hhaensel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hhaensel/32/1207_2.png) [@hhaensel](https://discourse.julialang.org/u/hhaensel)\
**Post date:** [March 24, 2024, 1:39pm UTC](https://discourse.julialang.org/t/macros-to-fill-keyword-arguments/25454/6 "2024-03-24T13:39:35Z")

</div>

Thanks for your reply. My use case is a bit different, but very similar.  
I want to supply multiple kwargs by calling a single macro.  
I know that it is possible if I splat outside the macro call, but that is not convenient for my use case, because the second argument of the macro is long. E.g. I’d like to

```julia
f(x, a = "a", @g y [
    card(1)
    card(2)
])

```

to result in

```julia
f(x, a = "a", y = y, f2([
    card(1)
    card(2)
]))

```

So the macro splatting should work without preceding ‘;’ and should supply first a kwarg and then a positional argument.  
Unfortunately, passing `:((Expr(:kw, :y, y), f2(x2))...)` nor `:((:y => y, f2(x2))...)` works because splatting of Pairs into kwargs only works after a ‘;’ character.  
I think something like `esc(x, y) would need to be allowed from the Julia side.

---

<div class="post-metadata">

**Author:** ![vchuravy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vchuravy/32/8_2.png) [@vchuravy](https://discourse.julialang.org/u/vchuravy)\
**Post date:** [August 20, 2025, 4:40pm UTC](https://discourse.julialang.org/t/macros-to-fill-keyword-arguments/25454/7 "2025-08-20T16:40:10Z")

</div>

You were likely missing `arg[1]` to actually construct the right expression.

```julia-auto
macro passkwargs(kwargs...)
    foreach(kwargs) do kwarg
        if !(kwarg isa Expr && kwarg.head === :(=))
            throw(ArgumentError("`@passkwargs` only accepts keyword arguments, got: $kwarg"))
        end
        kwarg.head = :kw
    end
    esc(quote
        (; $(kwargs...))
    end)
end

```
