Typed keyword vararg

g(;kwargs::Int...) = println(kwargs)

julia> g(x=1,y=2)
ERROR: MethodError: no method matching #g#16(::Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol,Symbol},NamedTuple{(:x, :y),Tuple{Int64,Int64}}}, ::typeof(g))
Closest candidates are:
  #g#16(::Int64, ::Any) at none:1
Stacktrace:
 [1] (::getfield(Main, Symbol("#kw##g")))(::NamedTuple{(:x, :y),Tuple{Int64,Int64}}, ::typeof(g)) at ./none:0
 [2] top-level scope at none:0

can’t I have an typed keyword vararg?

Thanks

I don’t know the answer, but here’s an old stack overflow question. The workings of kwargs have changed since then though, so I don’t know if it’s still relevant, but at the time this wasn’t possible.

The manual still says that kwargs don’t participate in dispatch, so you might achieve the same ends by just checking in the body of the function

We know here that the type of kwargs is Iterator.Pairs; therefore, it can not be restrict to type Int.
I think the feasible way should be:
g(;kwargs::T...) where {T<:AbstractDict{Symbol, Int}} = println(kwargs)
test:

julia> g(x=1, y=2, z=3)
Base.Iterators.Pairs(:x=>1,:y=>2,:z=>3)

julia> g(x=1, y=2.5)
ERROR: MethodError: no method matching #g#3(::Base.Iterators.Pairs{Symbol,Real,Tuple{Symbol,Symbol},NamedTuple{(:x, :y),Tuple{Int64,Float64}}}, ::typeof(g))
Closest candidates are:
  #g#3(::T<:AbstractDict{Symbol,Int64}, ::Any) where T<:AbstractDict{Symbol,Int64} at REPL[1]:1
Stacktrace:
 [1] (::getfield(Main, Symbol("#kw##g")))(::NamedTuple{(:x, :y),Tuple{Int64,Float64}}, ::typeof(g)) at .\none:0
 [2] top-level scope at none:0

julia>
1 Like

this looks a bit convoluted. It’s not like you can pass non-AbstractDict to kwargs right?

you can but you have do this like
f(;dict…)

Is there a way to do this with more than one type of kwarg?

If the type of kwargs is more than one, the second parameter of AbstractDict should be a abstract type that are the supertype of kwargs’ type; such as AbstractDict{Symbol, Real} for g(x=1.0, y=1).

If the type of the keywords is more arbitrary, there is no need to add a parameter type Abstract{Symbol, Any}. After all, function keywords do not participate in the dispatch.

Further, not adding keyword type does not affect the speed of the function, as long as the set of keyword parameters has been run once (compiled).

1 Like

However there is an issue:

julia> handle_kva(d::D) where {D<:AbstractDict{Symbol,T}} where T = println(d)
handle_kva (generic function with 1 method)

julia> f(;kwargs...) = handle_kva(kwargs)
f (generic function with 1 method)

julia> f(;x=1)
Base.Iterators.Pairs(:x=>1)

julia> f()
ERROR: MethodError: no method matching handle_kva(::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}})
Closest candidates are:
  handle_kva(::D<:AbstractDict{Symbol,T}) where {T, D<:AbstractDict{Symbol,T}} at REPL[1]:1
Stacktrace:
 [1] #f#3(::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::Function) at ./REPL[2]:1
 [2] f() at ./REPL[2]:1
 [3] top-level scope at none:0

I assume you can solve it by handle_kva(d::D) where {D<:AbstractDict{M,T}} where {M,T} = Dict{Symbol,Any}()

but still It would be awesome to solve it on the function signature.

Is your question about the exception of empty keyword parameter?

I test that the type of kwargs is subtype of AbstractDict{Union{}, Union{}} where keyword parameter is empty. So may be Union{AbstractDict{Union{}, Union{}}, AbstractDict{Symbol, Int}} could be used to consider the exception.

Wow, this type expression looks very long.