Pass function arguments in tuple, how to manage keyword arguments

I have a function with some optional keyword arguments.

function f1(a::Int, b::Float64; c::Int=42, d::Int=43)

Another top level function may sometimes call f1, but I don’t want to bother the user with specifying f1’s arguments if they’re not necessary. And when the arguments are required, I want to make it as easy to manage as possible.
This is my partial solution so far

function f_top(call_f1::Bool; f1_params::Union{Tuple,Nothing}=nothing)
    if call_f1
        isnothing(f1_params) && throw(ArgumentError)
        f1(f1_params...)
    end
end

So this works

f1_params = (1, 2.0)
f_top(true, f1_params=f1_params)

But what if I want to specify c and/or d? Doesn’t seem possible using this approach. Is there a more idiomatic solution to this type of problem?

(This is obviously a MWE and in my real problem f1 has around 20 parameters. It’s actually a constructor for a struct).

How about

function f_top(call_f1::Bool; f1_params::Union{Tuple,Nothing}=nothing, f2_kwargs...)
    if call_f1
        isnothing(f1_params) && throw(ArgumentError)
        f1(f1_params...; f2_kwargs...)
    end
end

with f1(a::Int, b::Float64; c::Int=42, d::Int=43) = a+b+c+d

julia> f_top(true, f1_params=(1,2.0), c=3)
49.0

For many keyword arguments that are passed around/downstream this way, it is common to wrap them in a struct defined for the purpose. Base.@kwdef provides a nice interface for construction.

1 Like

Beautiful, Base.@kwdef is perfect! Thanks.

My focus here is to develop the nicest possible interface, so that my reluctant colleagues have no excuses not to start using julia.

Can you provide an example how it works using Base.@kwdef ?

It could look like this:

julia> Base.@kwdef struct Params
           a :: Int      # Mandatory arguments
           b :: Float64
           c :: Int = 42 # Optional arguments with a default value
           d :: Int = 43
       end
Params

julia> function f1(p::Params)
           # get the arguments values from the fields of p
           p.a * p.b + p.c - p.d
       end
f1 (generic function with 1 method)

# instantiate a set of parameters
# (c will get its default value)
julia> p = Params(a=1, b=3.14, d=12)
Params(1, 3.14, 42, 12)

# call f1 with these parameters
julia> f1(p)
33.14

Beware: IIRC Base.@kwdef is not part of Julia’s public API