Is slurpping typed keyword args invalid?

Slurrping keyword args is a fairly common usage:

julia> foo(; x...) = 1
foo (generic function with 1 method)

julia> foo()
1

But, if I annotate with type, then this function becomes non-callable…

julia> bar(; x::Int...) = 2
bar (generic function with 1 method)

julia> bar()
ERROR: MethodError: no method matching #bar#141(::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::typeof(bar))
Closest candidates are:
  #bar#141(::Int64, ::typeof(bar)) at REPL[52]:1

So I guess this is not a valid usage but if that’s the case then why it didn’t stop me from defining the function?

1 Like

Assuming that what you want by bar(; x::Int...) is that the value of the keyword arguments be Int, then I think you’re looking for:

bar(;x::Pairs{<:Any,<:Int}...) = ...

Note the <:Int instead of just Int makes it so it accepts bar() with no arguments (you can figure this out by defining bar(;x...) = typeof(x) and seeing that bar() returns a Pairs{Union{},Union{}} which is <:Pairs{<:Any,<:Int}, but not <:Pairs{<:Any,Int})

3 Likes

I should have mentioned that I was actually expecting it to be a valid usage.

@marius311 That’s a nice workaround!

julia> bar(; x::Iterators.Pairs{<:Any,<:Int}...) = isempty(x) ? 0 : sum(values(x))

julia> bar()
0

julia> bar(; x = 1, y = 2)
3

ulia> bar(; x = 1, y = 3.0)
ERROR: MethodError: no method matching #bar#192(::Base.Iterators.Pairs{Symbol,Real,Tuple{Symbol,Symbol},NamedTuple{(:x, :y),Tuple{Int64,Float64}}}, ::typeof(bar))
1 Like

I am not sure this is part of the exposed API though — if not, the representation could change at any point.

3 Likes