KeywordCalls.jl icon indicating copy to clipboard operation
KeywordCalls.jl copied to clipboard

Default values bug with multiple `@kwcall`

Open mileslucas opened this issue 4 years ago • 1 comments

Oh no, I think there's a bug hidden inside the default values-

julia> using KeywordCalls
julia> foo(nt::NamedTuple{(:a, :b)}) = nt.a + nt.b
julia> foo(nt::NamedTuple{(:c, :d)}) = nt.c * nt.d
julia> @kwcall foo(a, b=0)
julia> foo(a=2)
2
julia> foo(a=4, b=10)
14

second @kwcall

julia> @kwcall foo(c, d=0)
julia> foo(c=2)
0
julia> foo(c=4, d=1)
4

but now the foo(a,b) defaults are lost-

julia> foo(a=2)
ERROR: MethodError: no method matching _call_in_default_order(::typeof(foo), ::NamedTuple{(:a, :d), Tuple{Int64, Int64}})
Closest candidates are:
  _call_in_default_order(::typeof(foo), ::NamedTuple{(:a, :b), T} where T<:Tuple) at C:\Users\miles\.julia\packages\KeywordCalls\d3x9F\src\KeywordCalls.jl:40
  _call_in_default_order(::typeof(foo), ::NamedTuple{(:c, :d), T} where T<:Tuple) at C:\Users\miles\.julia\packages\KeywordCalls\d3x9F\src\KeywordCalls.jl:40
Stacktrace:
 [1] foo(nt::NamedTuple{(:d, :a), Tuple{Int64, Int64}})
   @ Main C:\Users\miles\.julia\packages\KeywordCalls\d3x9F\src\KeywordCalls.jl:41
 [2] foo(; kw::Base.Iterators.Pairs{Symbol, Int64, Tuple{Symbol}, NamedTuple{(:a,), Tuple{Int64}}})
   @ Main C:\Users\miles\.julia\packages\KeywordCalls\d3x9F\src\KeywordCalls.jl:42
 [3] top-level scope
   @ REPL[27]:1

mileslucas avatar May 23 '21 20:05 mileslucas

I see, it's the middle line here:

q = quote
        KeywordCalls._call_in_default_order(::typeof($f), nt::NamedTuple{($(sorted_args...),)}) = $f(NamedTuple{($(args...),)}(nt))
        $f(nt::NamedTuple) = KeywordCalls._call_in_default_order($f, _sort(merge($defaults, $alias($f, nt))))
        $f(; kw...) = $f(merge($defaults, $alias($f, NamedTuple(kw))))
    end

There can only be one f(nt::NamedTuple) method, so it's rewritten each time

cscherrer avatar May 24 '21 00:05 cscherrer