# Unpack NamedTuple into a function definition

**URL:** <https://discourse.julialang.org/t/unpack-namedtuple-into-a-function-definition/97500>\
**Category:** General Usage\
**Tags:** question\
**Created:** [April 15, 2023, 1:47am UTC](https://discourse.julialang.org/t/unpack-namedtuple-into-a-function-definition/97500 "2023-04-15T01:47:07Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![cadojo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cadojo/32/25328_2.png) [@cadojo](https://discourse.julialang.org/u/cadojo)\
**Post date:** [April 15, 2023, 1:47am UTC](https://discourse.julialang.org/t/unpack-namedtuple-into-a-function-definition/97500/1 "2023-04-15T01:47:07Z")

</div>

I am writing a Julia package to implement a REST API, and I have the accepted parameters available as `NamedTuple` constants. I’d like to have these `NamedTuple` constants _double_ as the default keyword arguments for a function. I’d rather not just write a generic `kwargs...` in the definition, because it would be handy to have the user be able to tab-complete the acceptable parameters.

Is this possible, possibly with macro magic? I’d like the two definitions of `query` below to be identical at runtime.

```julia
const PARAMETERS = (; a = 1, b = 2)

function query(; PARAMETERS...)
  ...
end

function query(; a = 1, b = 2)
  ...
end

```

I’ve tried the following, and I think I’m close, but for some reason the character `"` is being interpolated into the expression.

```julia
julia> @eval f(; $(replace(string(p), "("=>"", ")"=>""))) = a + b
ERROR: syntax: invalid keyword argument syntax ""a = 1, b = 2""
Stacktrace:
 [1] top-level scope
   @ none:1
 [2] eval(m::Module, e::Any)
   @ Core ./boot.jl:370
 [3] top-level scope
   @ REPL[46]:1

```

---

<div class="post-metadata">

**Author:** ![Jollywatt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jollywatt/32/202198_2.png) [@Jollywatt](https://discourse.julialang.org/u/Jollywatt)\
**Post date:** [April 15, 2023, 6:21am UTC](https://discourse.julialang.org/t/unpack-namedtuple-into-a-function-definition/97500/2 "2023-04-15T06:21:45Z")

</div>

This is an interesting question! I’ll point out some suspected confusion: when metaprogramming in Julia, code is not represented with strings, but rather expression trees. If you interpolate a string into `@eval`, you’ll get a literal string:

```julia
julia> e = "2 + 2"
"2 + 2"

julia> :( a = $e ) # this is what `@eval a = $e` would execute
:(a = "2 + 2")

julia> e = :(2 + 2) # instead, deal with expressions
:(2 + 2)

julia> :( a = $e )
:(a = 2 + 2)

```

You’d never represent code as a string unless it comes to you that way — in which case you can `Meta.parse` it into an expression.

* * *

On to the question: you have a named tuple which you want to use as default keyword arguments for some method definitions:

```julia
const PARAMETERS = (; a = 1, b = 2)

function query(; a = 1, b = 2) # you don’t want to repeat yourself here
  a + b
end

```

One way to do this is like so:

```julia
const PARAMETERS = (; a = 1, b = 2)

kws = [Expr(:kw, k, v) for (k, v) in pairs(PARAMETERS)]

@eval function query(; $(kws...))
    a + b
end

```

You can see the unevaluated code by replacing `@eval` with `quote … end`. This requires a little knowledge of how keyword arguments are parsed internally, so I’ll explain how I got there.

If you inspect the structure of an expression with keyword arguments, you’ll see they’re actually `Expr(:kw, k, v)` objects.

```julia
julia> :( f(; a = 1) ) |> dump
Expr
  head: Symbol call
  args: Array{Any}((2,))
    1: Symbol f
    2: Expr
      head: Symbol parameters
      args: Array{Any}((1,))
        1: Expr
          head: Symbol kw
          args: Array{Any}((2,))
            1: Symbol a
            2: Int64 1

julia> :( f(; a = 1, b = 2) ).args[2].args # these are the `a = 1, b = 2`
2-element Vector{Any}:
 :($(Expr(:kw, :a, 1)))
 :($(Expr(:kw, :b, 2)))

```

To properly interpolate `(; a = 1, b = 2)` into an expression as keyword arguments, we have to convert them into a collection of `Expr(:kw, k, v)` structs. That is what the `kws` line above does. Finally, the dot syntax in `f(; $(kws...))` is equivalent to `f(; $(kws[1]), $(kws[2]), …, $(kws[end]))`. Hope this helps.

---

<div class="post-metadata">

**Author:** ![cadojo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cadojo/32/25328_2.png) [@cadojo](https://discourse.julialang.org/u/cadojo)\
**Post date:** [April 15, 2023, 2:43pm UTC](https://discourse.julialang.org/t/unpack-namedtuple-into-a-function-definition/97500/3 "2023-04-15T14:43:57Z")

</div>

Thanks for the super detailed reply!

---

<div class="post-metadata">

**Author:** ![HanD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hand/32/213908_2.png) [@HanD](https://discourse.julialang.org/u/HanD)\
**Post date:** [April 17, 2023, 1:36pm UTC](https://discourse.julialang.org/t/unpack-namedtuple-into-a-function-definition/97500/4 "2023-04-17T13:36:39Z")

</div>

@Jollywatt gave a very detailed and accurate answer.

There is an alternative approach, which does not require macros at all. The basic idea is to add two methods, one that handles keyword arguments, and another, that accepts single a named tuple argument. Here’s how:

```julia
julia> const PARAMETERS = (a = 1, b = 2)
(a = 1, b = 2)

julia> query(; kwargs...) = query(merge(PARAMETERS, kwargs))
query (generic function with 1 method)

julia> query(params::typeof(PARAMETERS)) = println(params)
query (generic function with 2 methods)

julia> query(a = 4)
(a = 4, b = 2)

```
