# Splitting kwargs into specific keyword arguments?

**URL:** <https://discourse.julialang.org/t/splitting-kwargs-into-specific-keyword-arguments/90131>\
**Category:** General Usage\
**Created:** [November 11, 2022, 5:11pm UTC](https://discourse.julialang.org/t/splitting-kwargs-into-specific-keyword-arguments/90131 "2022-11-11T17:11:14Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![TTolppanen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ttolppanen/32/12568_2.png) [@TTolppanen](https://discourse.julialang.org/u/TTolppanen)\
**Post date:** [November 11, 2022, 5:11pm UTC](https://discourse.julialang.org/t/splitting-kwargs-into-specific-keyword-arguments/90131/1 "2022-11-11T17:11:14Z")

</div>

Let’s say I have these two functions:

```julia
function funA(; a=2.0)
    #something
end

function funB(; b=4.0)
    #something
end

```

They both take keywords arguments with default values. Now if I want to use these in a third function

```julia
function useAB(; a, b)
    return funA(;a=a) + funB(;b=b)
end

```

how could I write the third function `useAB` so that if I dont pass either `a` or `b` it defaults to using `funA` with its default value or `funB` with its default value? So I want to be able use `useAB()`, so that `useAB()` is equivalent to `funA() + funB()`, while being able to also have `useAB(;a=3)` to be equivalent to `funA(;a=3) + funB()` etc. I understand I could just have

```julia
function useAB(;a=2.0, b=4.0)
    #something
end

```

where the default values are the same, but the problem is that I don’t want to change the default values in two places if needed, or if e.g. `funA` is something sophisticated that does something specific when no arguments are passed(?).

Anyways, I started doing this by using

```julia
function useAB(;kwargs...)
    #something
end

```

and splitting the kwargs properly for the two functions, but the way I did it was very complicated. Also there is a danger of passing wrongly written arguments without the user noticing it. Is there a nice way of achieving this? Or should I somehow avoid this completely? If so, how?

Thank you for your time.

---

<div class="post-metadata">

**Author:** ![bgroenks](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bgroenks/32/21784_2.png) [@bgroenks](https://discourse.julialang.org/u/bgroenks)\
**Post date:** [November 11, 2022, 8:20pm UTC](https://discourse.julialang.org/t/splitting-kwargs-into-specific-keyword-arguments/90131/2 "2022-11-11T20:20:25Z")

</div>

As far as I am aware, this is not currently possible. You [cannot dispatch on keyword arguments](https://discourse.julialang.org/t/how-can-kwargs-be-used-in-multiple-dispatch/86790/3) in general.

One workaround, off the top of my head, if you don’t mind using positional arguments for `funA` and `funB`:

```julia
funA(a=2.0) = a
funA(::Nothing) = funA()
funB(b=4.0) = b
funB(::Nothing) = funB()
useAB(; a=nothing, b=nothing) = funA(a) + funB(b)

```

---

<div class="post-metadata">

**Author:** ![mtfishman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mtfishman/32/30755_2.png) [@mtfishman](https://discourse.julialang.org/u/mtfishman)\
**Post date:** [November 11, 2022, 8:22pm UTC](https://discourse.julialang.org/t/splitting-kwargs-into-specific-keyword-arguments/90131/3 "2022-11-11T20:22:41Z")

</div>

Something I have done is separate out the default values into separate functions, i.e.:

```julia
default_a() = 2.0
default_b() = 4.0
function funA(; a=default_a())
    #something
end
function funB(; b=default_b())
    #something
end
function useAB(;a=default_a(), b=default_b())
    return funA(; a) + funB(; b)
end

```

Then if I change the default values I only have to change it in one location.

Another advantage of this is that some keyword argument defaults depend on the values of other arguments, so the functions can handle that.

I’m curious how other people handle this situation.

---

<div class="post-metadata">

**Author:** ![TTolppanen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ttolppanen/32/12568_2.png) [@TTolppanen](https://discourse.julialang.org/u/TTolppanen)\
**Post date:** [November 11, 2022, 9:15pm UTC](https://discourse.julialang.org/t/splitting-kwargs-into-specific-keyword-arguments/90131/4 "2022-11-11T21:15:01Z")

</div>

Thanks for the ideas. The problem that I have with what @bgroenks suggested is that if `funA` and `funB` have several arguments, I would need to manually define every combination of them right? And then every combination again with `useAB` which would be a lot of work even for a couple of variables.

The problem that I have with what @mtfishman suggested is that I want to use the default values of a function I haven’t defined. So when I don’t pass any arguments I want the functions that I haven’t made to default to the behavior that they have when no arguments are passed.

I tried this approach:

```julia
function splitkwargs(kwargs, args...)
    for f in args
        isa(f, Function) ? nothing : throw(ArgumentError("args are not functions"))
    end
    allkwargs = []
    for f in args
        fkwargs = Base.kwarg_decl(first(methods((f)))) #gets the keyword arguments
        length(fkwargs) == 0 ? throw(ArgumentError(String(Symbol(f)) * " has no key-word arguments")) : push!(allkwargs, fkwargs)
    end
    allkwargs = [Base.kwarg_decl(first(methods((f)))) for f in args]
    wrongKeywordArguments = setdiff(keys(kwargs), union(allkwargs...))
    if length(wrongKeywordArguments) != 0 
        throw(UndefKeywordError(wrongKeywordArguments[1]))
    end
    out = []
    for kwarg in allkwargs
        #this puts the proper kwargs specific to a function in an array
        push!(out, (;[(key, kwargs[key]) for key in intersect(keys(kwargs), kwarg)]...))
    end
    if length(out) == 1
        return out[1]
    end
    return out
end

```

and you could use it like this

```julia
function useAB(; kwargs...)
    fAkwargs, fBkwargs = splitkwargs(kwargs, funA, funB)
    return funA(;fAkwargs...) + funB(;fBkwargs...)

```

I think it does what it is supposed to, BUT I tried using it with the `apply` function from the `ITensors` package and ran into the issue that apparently `apply` doesn’t have any keyword arguments. I read little bit about their code and they did something that when something like this

```julia
function apply(;kwargs...)
    keyarg1 = get(kwargs, :keyarg1)...
    #etc with the other args

```

So I guess they do not specify the keyword arguments so that the `splitkwargs` function doesn’t find them.

So I am not sure what to do about this. I think maybe I could use the `splitkwargs` function but pass the keywords that I want in arrays of symbols instead of trying to fetch them from the functions.

What do you think?

---

<div class="post-metadata">

**Author:** ![jd-foster](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jd-foster/32/35824_2.png) [@jd-foster](https://discourse.julialang.org/u/jd-foster)\
**Post date:** [November 13, 2022, 11:22am UTC](https://discourse.julialang.org/t/splitting-kwargs-into-specific-keyword-arguments/90131/5 "2022-11-13T11:22:22Z")

</div>

Here is an approach that you may be able to adapt to you needs.

We can define a “keyword-based constructor” for a `struct` type with default values as follows:

```julia
julia> Base.@kwdef struct Options
           a::Float64 = 2.1
           b::Int64 = 4
           c::String = "defaults"
       end
Options

julia> Options()
Options(2.1, 4, "defaults")

julia> Options(b = 16, c = "new settings")
Options(2.1, 16, "new settings")

```

Now define your specialised function like

```julia
julia> function funA(; opt = (; a))
           println("Value of option 'a' is: ", opt.a)
       end
funA (generic function with 1 method)

```

and so

```julia
julia> funA(; opt = Options())
Value of option 'a' is: 2.1

julia> funA(; opt = Options(a = 3.4))
Value of option 'a' is: 3.4

```

where the [destructuring](https://docs.julialang.org/en/v1/manual/functions/#destructuring-assignment) that occurs in `funA` only “sees” the `a` parameter, and accesses the default value automatically.

Similarly, you can define

```julia
julia> function funB(; opt = (; b))
           println("Value of option 'b' is: ", opt.b)
       end
funB (generic function with 1 method)

julia> funB(; opt = Options())
Value of option 'b' is: 4

```

which is selective for the relevant option `b`; now, this case be extended to the combined case

```julia
julia> function funAB(; opt = (; a, b))
           println("The sum of options 'a' and 'b' are: ", opt.a + opt.b)
       end
funAB (generic function with 1 method)

julia> funAB(; opt = Options())
The sum of options 'a' and 'b' are: 6.1

julia> funAB(; opt = Options(a=10, b=23))
The sum of options 'a' and 'b' are: 33.0

```

Another advantage of passing the `Options` struct is that you can define highly flexible [Inner Constructor Methods](https://docs.julialang.org/en/v1/manual/constructors/#man-inner-constructor-methods) to implement other logic.

EDIT: note also that if you want to be able to just call e.g. `funA()`, then you need an auxiliary definition like  
`funA() = funA(; opt = Options())`

---

<div class="post-metadata">

**Author:** ![simsurace](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simsurace/32/30216_2.png) [@simsurace](https://discourse.julialang.org/u/simsurace)\
**Post date:** [November 13, 2022, 12:05pm UTC](https://discourse.julialang.org/t/splitting-kwargs-into-specific-keyword-arguments/90131/6 "2022-11-13T12:05:07Z")

</div>

Another option is this:

```julia
function funA(; a=2.0, kwargs…)
    #something
end

function funB(; b=4.0, kwargs…)
    #something
end

function useAB(; kwargs…)
    return funA(; kwargs…) + funB(; kwargs…)
end

```

Then whatever keywords are passed to `useAB` will be forwarded, and the others will use the default. If you use this approach, you have to use a set of unambiguous global keywords, as all functions can potentially see all keywords injected at the top function call.

---

<div class="post-metadata">

**Author:** ![jd-foster](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jd-foster/32/35824_2.png) [@jd-foster](https://discourse.julialang.org/u/jd-foster)\
**Post date:** [November 13, 2022, 12:09pm UTC](https://discourse.julialang.org/t/splitting-kwargs-into-specific-keyword-arguments/90131/7 "2022-11-13T12:09:48Z")

</div>

If I read the OP correctly, they don’t want default values to be “attached” to the function definition in order to avoid multiple locations of definitions.

---

<div class="post-metadata">

**Author:** ![simsurace](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simsurace/32/30216_2.png) [@simsurace](https://discourse.julialang.org/u/simsurace)\
**Post date:** [November 13, 2022, 12:13pm UTC](https://discourse.julialang.org/t/splitting-kwargs-into-specific-keyword-arguments/90131/8 "2022-11-13T12:13:48Z")

</div>

If you are responding to my post, it favors putting the default values at the lowest possible level, i.e. where the variable appears in the function body, and only there.

---

<div class="post-metadata">

**Author:** ![TTolppanen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ttolppanen/32/12568_2.png) [@TTolppanen](https://discourse.julialang.org/u/TTolppanen)\
**Post date:** [November 13, 2022, 12:47pm UTC](https://discourse.julialang.org/t/splitting-kwargs-into-specific-keyword-arguments/90131/9 "2022-11-13T12:47:54Z")

</div>

Thanks for the suggestions. I like what @simsurace said, with that the default values will be defined only once and at the lowest level. But if there is a typo in the keyword when using `useAB`, will the `kwargs...` slurp in the misspelled keyword and not notify me about it? I don’t like being able to mistype a keyword and not be told about it, but maybe I’m too worried about it.

One problem I still have is that what would you do in the case where `funB` is a function from some package, so that it is defined without `kwargs` and I can’t access it to change it to be like that? So let’s say that in `useAB` I want to use the function `funA` defined by me, and the function `notMyFunB` which is not made by myself, so that I cannot change the argument definitions of `notMyFunB`, and `notMyFunB` takes in the kwarg `b`. How could I define the arguments in `useAB` so that when no kwargs are passed it uses the default values of `funA` and `notMyFunB`, but It would also be possible the pass the individual kwargs too? Sorry if this is getting confusing. I wish it would be as simple as

```julia
function useAB(; a=Nothing, b=Nothing)
    return funA(;a) + funB(;b)
end

```

without me having to explicitly define `funA(::Nothing) = funA()`, which gets tricky when `funA` has several kwargs.

---

<div class="post-metadata">

**Author:** ![TTolppanen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ttolppanen/32/12568_2.png) [@TTolppanen](https://discourse.julialang.org/u/TTolppanen)\
**Post date:** [November 14, 2022, 11:03am UTC](https://discourse.julialang.org/t/splitting-kwargs-into-specific-keyword-arguments/90131/10 "2022-11-14T11:03:33Z")

</div>

I ended up using this

```julia
function splitkwargs(kwargs, args...)
    for f in args
        isa(f, Array{Symbol}) ? nothing : throw(ArgumentError("args are not arrays of symbols"))
    end
    wrongKeywordArguments = setdiff(keys(kwargs), union(args...))
    if length(wrongKeywordArguments) != 0 
        throw(UndefKeywordError(wrongKeywordArguments[1]))
    end
    out = []
    for kwarg in args
        push!(out, (;[(key, kwargs[key]) for key in intersect(keys(kwargs), kwarg)]...))
    end
    return length(out) == 1 ? out[1] : out
end

```

which could be used here like so:

```julia
function useAB(: kwargs...)
    #notmyfun has kwargs {calc, norm}
    funAkwargs, funBkwargs, notmyfunkwargs = splitkwargs(kwargs, [:a], [:b], [:calc, :norm])
    return funA(;funAkwargs...) + funB(;funBkwargs...) + notmyfun(;notmyfunkwargs...)

```

I’m not sure if there will be some problems with this approach, but oh well…

---

<div class="post-metadata">

**Author:** ![simsurace](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simsurace/32/30216_2.png) [@simsurace](https://discourse.julialang.org/u/simsurace)\
**Post date:** [November 14, 2022, 9:24pm UTC](https://discourse.julialang.org/t/splitting-kwargs-into-specific-keyword-arguments/90131/11 "2022-11-14T21:24:54Z")

</div>

> [@TTolppanen](#):
>
> But if there is a typo in the keyword when using `useAB`, will the `kwargs...` slurp in the misspelled keyword and not notify me about it? I don’t like being able to mistype a keyword and not be told about it, but maybe I’m too worried about it.

That‘s probably the main issue of the solution I proposed, and depending on the application, it could be quite serious.

I haven‘t tested this, but I think you should be able to check the keyword validity at the top entry point along the lines of `issubset(keys(kwargs), VALID_KEYWORDS)`, where the second argument is a global constant list of `Symbol`s, and throw an error otherwise. This prevents your mistyped options from being silently ignored. But to be sure, I would still recommend unit-testing all options for correct behavior even if typed correctly, as it is easy to forget to forward the kwargs.
