3
votes

Is there a way to check if a function has keywords arguments in Julia? I am looking for something like has_kwargs(fun::Function) that would return true if fun has a method with keyword arguments.

The high level idea is to build a function:

function master_fun(foo::Any, fun::Function, ar::Tuple, kw::Tuple)
    if has_kwargs(fun)
        fun(ar... ; kw...)    
    else 
        fun(ar...)
    end
end
2
Why do you need to build a function that way? I don't know what foo is, but what about using default values: ar::Tuple=(), kw::Tuple=()? If fun has kwargs, presumably kw holds them (in your example).Jeffrey Sarnoff
I have an issue open relating to this: github.com/JuliaLang/julia/issues/20555Lyndon White
Thanks for your answer, using kw = () raises a BoundsError if you pass it to a function.Maxime

2 Answers

3
votes

Basically, @Michael K. Borregaard's suggestion to use try-catch is correct and officially works.

Looking into the unofficial implementation details, I came up with the followng:

haskw(f,tup) = isdefined(typeof(f).name.mt,:kwsorter) &&
  length(methods(typeof(f).name.mt.kwsorter,(Vector{Any},typeof(f),tup...)))>0

This function first looks if there is any keyword processing on any method of the generic function, and if so, looks at the specific tuple of types.

For example:

julia> f(x::Int) = 1
f (generic function with 1 method)

julia> f(x::String ; y="value") = 2
f (generic function with 2 methods)

julia> haskw(f,(Int,))
false

julia> haskw(f,(String,))
true

This should be tested for the specific application, as it probably doesn't work when non-leaf types are involved. As Michael commented, in the question's context the statement would be:

if haskw(fun, typeof.(ar))
    ...
2
votes

I don't think you can guarantee that a given function has keyword arguments. Check

f(;x = 3) = println(x)
f(x) = println(2x)
f(3)
   #6

f(x = 3)
   #3 

f(3, x = 3)
    #ERROR: MethodError: no method matching f(::Int64; x=3)
    #Closest candidates are:
    #  f(::Any) at REPL[2]:1 got unsupported keyword argument "x"
    #  f(; x) at REPL[1]:1

So, does the f function have keywords? You can only check for a given method. Note that, in your example above, you'd normally just do

function master_fun(foo, fun::Function, ar::Tuple, kw....)
    fun(ar... ; kw...)
end

which should work, and if keywords are passed to a function that does not take them you'd just leave the error reporting to fun. If that is not acceptable you could try to wrap the fun(ar...; kw...) in a try-catch block.