# Why do Julia functions handle keyword arguments as \`Base.Pairs\` instead of \`NamedTuple\` or \`Dict\`?

**URL:** <https://discourse.julialang.org/t/why-do-julia-functions-handle-keyword-arguments-as-base-pairs-instead-of-namedtuple-or-dict/102263>\
**Category:** General Usage\
**Tags:** argument, function, functions, keyword-arguments\
**Created:** [July 30, 2023, 4:08am UTC](https://discourse.julialang.org/t/why-do-julia-functions-handle-keyword-arguments-as-base-pairs-instead-of-namedtuple-or-dict/102263 "2023-07-30T04:08:35Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![singularitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/singularitti/32/17678_2.png) [@singularitti](https://discourse.julialang.org/u/singularitti)\
**Post date:** [July 30, 2023, 4:08am UTC](https://discourse.julialang.org/t/why-do-julia-functions-handle-keyword-arguments-as-base-pairs-instead-of-namedtuple-or-dict/102263/1 "2023-07-30T04:08:35Z")

</div>

In Python, where we use `*args` and `**kwargs` to handle an arbitrary number of positional and keyword arguments in a function. In Python, these positional arguments are gathered into a tuple, and keyword arguments are gathered into a dictionary:

```python
def my_function(*args, **kwargs):
    return args, kwargs

result = my_function(1, 2, 3, a=4, b=5, c=6)
print(result) # Outputs: ((1, 2, 3), {'a': 4, 'b': 5, 'c': 6})

```

However, in Julia it is different

```julia
function my_function(args...; kwargs...)
    return args, kwargs
end

my_function(1, 2, 3, a=4, b=5, c=6)
# Outputs: ((1, 2, 3), Base.Pairs(:a => 4, :b => 5, :c => 6))

```

Here, I see that the keyword arguments are returned as a `Base.Pairs` object, not a `NamedTuple` or a `Dict` as I expected.

Why does Julia use `Base.Pairs` to capture keyword arguments instead of `NamedTuple` or `Dict`? What are the benefits or use cases of `Base.Pairs` in this context?

---

<div class="post-metadata">

**Author:** ![longemen3000](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/longemen3000/32/7298_2.png) [@longemen3000](https://discourse.julialang.org/u/longemen3000)\
**Post date:** [July 30, 2023, 5:02am UTC](https://discourse.julialang.org/t/why-do-julia-functions-handle-keyword-arguments-as-base-pairs-instead-of-namedtuple-or-dict/102263/2 "2023-07-30T05:02:10Z")

</div>

related:

> <https://github.com/JuliaLang/julia/issues/25875>
>
> I'm probably misunderstanding something, but the current NEWS.md for julia-0.7 s…ays, under "new language features":
> 
> \> \* Named tuples, with the syntax (a=1, b=2). These behave very similarly to tuples, except components can also be accessed by name using dot syntax t.a \[...\]
> \> \* Keyword argument containers (kw in f(; kw...)) are now named tuples. \[...\]
> 
> But when I define a function that returns its keyword argument container \`kw\`, the returned object is not a named tuple:
> 
> \`\`\`julia
> \# named tuples do work
> julia\> t = (x=1, y=2)
> (x = 1, y = 2)
> 
> julia\> t.x
> 1
> 
> \# getting myself a keyword argument container
> julia\> f(;kw...) = kw
> f (generic function with 1 method)
> 
> julia\> t = f(x=1, y=2)
> pairs(::NamedTuple) with 2 entries:
> :x =\> 1
> :y =\> 2
> 
> \# can't access with the dot-syntax
> julia\> t.x
> ERROR: type Pairs has no field x
> Stacktrace:
> \[1\] getproperty(::Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol,Symbol},NamedTuple{(:x, :y),Tuple{Int64,Int64}}}, ::Symbol) at ./sysimg.jl:8
> \[2\] top-level scope
> 
> \# though by symbol works
> julia\> t\[:x\]
> 1
> \`\`\`
> 
> Could the NEWS.md be updated to say what the keyword argument container actually is? Thanks.
> 
> Obligatory
> \`\`\`
> julia\> versioninfo()
> Julia Version 0.7.0-DEV.3712
> Commit 80abd3dd89 (2018-02-04 03:26 UTC)
> Platform Info:
> OS: Linux (x86\_64-linux-gnu)
> CPU: AMD Ryzen 5 1600X Six-Core Processor
> WORD\_SIZE: 64
> LIBM: libopenlibm
> LLVM: libLLVM-3.9.1 (ORCJIT, znver1)
> Environment:
> \`\`\`

> <https://github.com/JuliaLang/julia/pull/25711>
>
> Ref discussion in #25675. This reverts "undo breaking change to kwargs iteration… order" (#25290) and makes keyword arguments regular ol' \`NamedTuple\`s again. This is breaking, since \`NamedTuple\`s iterate values rather than pairs (which motivated #25290) and so iteration of keyword arguments will be broken. Users who want the \`(name, value)\` iteration will need to use \`pairs\`.

---

<div class="post-metadata">

**Author:** ![singularitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/singularitti/32/17678_2.png) [@singularitti](https://discourse.julialang.org/u/singularitti)\
**Post date:** [July 30, 2023, 5:25am UTC](https://discourse.julialang.org/t/why-do-julia-functions-handle-keyword-arguments-as-base-pairs-instead-of-namedtuple-or-dict/102263/3 "2023-07-30T05:25:36Z")

</div>

As far as I understand [Change keyword arguments back to regular NamedTuples by ararslan · Pull Request #25711 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/25711), the use of `Pairs` in 2018 is that when you iterate those keyword arguments, iterating both `key` and `value` is more often desired, where `Pair` is the right choice. And iterating `NamedTuple`s only gives you the value of each item.

Kind of reasonable now.
