# Forwarding vs filtering kwargs

**URL:** https://discourse.julialang.org/t/forwarding-vs-filtering-kwargs/23196
**Category:** General Usage
**Tags:** kwargs
**Created:** [April 16, 2019, 9:59am UTC](https://discourse.julialang.org/t/forwarding-vs-filtering-kwargs/23196 "2019-04-16T09:59:10Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)
#### Post date: [April 16, 2019, 9:59am UTC](https://discourse.julialang.org/t/forwarding-vs-filtering-kwargs/23196/1 "2019-04-16T09:59:10Z")

</div>

When I want to forward kwargs from an API function to various internal dispatched methods I just allow them to have arbitrary kwargs, like so

```julia
external_api(x; kw...) = _internal(x; kw...)
_internal(x::Float64; kw1 = 1, kw...) #only needs kw1, but allows any other
_internal(x::Int; kw2 = 2, kw...) #only needs kw2, but allows any other

```

Is this the recommended pattern? The problem I see is that if I use a wrong keyword in the `external_api`, it will not complain. In other languages (e.g. Mathematica) there is a way to filter keywords allowed by a given function, so that if one uses a wrong keyword, it errors. Is there a similar pattern that one can use in Julia so that `external_api(x; kw3 = 3)` errors?

---

<div class="post-metadata">

### Author: ![mauro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mauro3/32/292_2.png) [@mauro3](https://discourse.julialang.org/u/mauro3)
#### Post date: [April 16, 2019, 11:33am UTC](https://discourse.julialang.org/t/forwarding-vs-filtering-kwargs/23196/2 "2019-04-16T11:33:15Z")

</div>

A bit off topic: What does Mathematica’s syntax for this look like?

---

<div class="post-metadata">

### Author: ![pfitzseb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pfitzseb/32/45566_2.png) [@pfitzseb](https://discourse.julialang.org/u/pfitzseb)
#### Post date: [April 16, 2019, 11:49am UTC](https://discourse.julialang.org/t/forwarding-vs-filtering-kwargs/23196/3 "2019-04-16T11:49:33Z")

</div>

You can always just write that yourself:

```julia
julia> allowed_kws = (:kw1, :kw2)
(:kw1, :kw2)

julia> function external_api(x; kws...)
           for kw in keys(kws)
               kw in allowed_kws || throw(KeyError(kw))
           end
           _internal(x, kws...)
       end
external_api (generic function with 1 method)

julia> _internal(x::Float64; kw1 = 1) = x+kw1
_internal (generic function with 2 methods)

julia> _internal(x::Int64; kw2 = 1) = x*kw1
_internal (generic function with 2 methods)

julia> external_api(2, kw3=3)
ERROR: KeyError: key :kw3 not found

```

---

<div class="post-metadata">

### Author: ![pablosanjose](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pablosanjose/32/7006_2.png) [@pablosanjose](https://discourse.julialang.org/u/pablosanjose)
#### Post date: [April 16, 2019, 1:05pm UTC](https://discourse.julialang.org/t/forwarding-vs-filtering-kwargs/23196/4 "2019-04-16T13:05:00Z")

</div>

Thanks @pfitzseb, I guess that’s always an option. I just wanted confirmation that I wasn’t missing a more “correct” approach

---

<div class="post-metadata">

### Author: ![mauro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mauro3/32/292_2.png) [@mauro3](https://discourse.julialang.org/u/mauro3)
#### Post date: [April 16, 2019, 1:14pm UTC](https://discourse.julialang.org/t/forwarding-vs-filtering-kwargs/23196/5 "2019-04-16T13:14:30Z")

</div>

You can also translate the keywords into a type, and then continue with that:

```julia
julia> Base.@kwdef struct Opts
       kw1 = 1
       kw2 = 1
       end
Opts

julia> function external_api(x; kws...)
       opts= Opts(;kws...)
       _internal(x, opts)
       end
external_api (generic function with 1 method)

julia> _internal(x, opts) = x +opts.kw1
_internal (generic function with 2 methods)

julia> external_api(4, kw1=7)
11

julia> external_api(4, kw3=7)
ERROR: MethodError: no method matching Opts(; kw3=7)
Closest candidates are:
  Opts(; kw1, kw2) at util.jl:728 got unsupported keyword argument "kw3"
  Opts(::Any, ::Any) at REPL[11]:2 got unsupported keyword argument "kw3"
Stacktrace:
 [1] kwerr(::NamedTuple{(:kw3,),Tuple{Int64}}, ::Type) at ./error.jl:125
 [2] (::getfield(Core, Symbol("#kw#Type")))(::NamedTuple{(:kw3,),Tuple{Int64}}, ::Type{Opts}) at ./none:0
 [3] #external_api#8(::Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol},NamedTuple{(:kw3,),Tuple{Int64}}}, ::Function, ::Int64) at ./REPL[12]:2
 [4] (::getfield(Main, Symbol("#kw##external_api")))(::NamedTuple{(:kw3,),Tuple{Int64}}, ::typeof(external_api), ::Int64) at ./none:0
 [5] top-level scope at none:0

```

If you use Paramters.jl’s `@unpack` at the top of each `_internal` method, then it is also pretty clear which options each method uses:

```julia
function _internal(x, opts)
  @unpack kw1 = opts
  ...
end

```

(I think if `Opts` was iterable, then kwargs and the `...` syntax could still be used for the internal methods.)
