Add method with different arguments to existing function?

Hi!

Suppose I have a function f(a::Number, b::Number; c=1, d=2.0, e="hello") and I want to add a method to it with different kwargs, but with the same positional arguments, say for example f(a::Number, b::Number; f="bye", g=pi, h=nothing).

Is this possible without overwriting the first method for f()?

No. Keyword arguments aren’t used for dispatch in Julia.

1 Like

I see, thanks for taking the time to answer!

Welcome!

Here are a couple workarounds you could use. Let us know if you need more help.

  1. Dump all the keyword arguments into one method and branch with if. (Not the best, but it works.)
julia> function f(a::Number, b::Number; c=nothing, d=nothing, e=nothing, f=nothing, g=nothing, h=nothing)
           if c !== nothing && d !== nothing && e !== nothing
               println.((c, d, e))
           elseif f !== nothing && g !== nothing && h !== nothing
               println.((f, g, h))
           else
               throw(ArgumentError("Missing required keyword argument."))
           end
           return a, b
       end
f (generic function with 1 method)

julia> f(1, 2; c=1, d=2.0, e="hello")
1
2.0
hello
(1, 2)

julia> f(1, 2; f="bye", g=pi, h=12)
bye
π
12
(1, 2)
  1. Create custom types and dispatch on those.
julia> struct Type1
           c::Int
           d::Float64
           e::String
       end

julia> struct Type2
           f::String
           g::Irrational{:π}
           h::Int
       end

julia> function f(a::Number, b::Number, c::Type1)
           println(c.e)
           return c
       end
f (generic function with 2 methods)

julia> function f(a::Number, b::Number, c::Type2)
           println(c.f)
           return c
       end
f (generic function with 3 methods)

julia> c1 = Type1(1, 2.0, "hello")
Type1(1, 2.0, "hello")

julia> c2 = Type2("bye", pi, 12)
Type2("bye", π, 12)

julia> f(1, 2, c1)
hello
Type1(1, 2.0, "hello")

julia> f(1, 2, c2)
bye
Type2("bye", π, 12)
  1. Make a function <good descriptive name here> for the second input set instead of another method of f.

Another option is to create your own singleton type to indicate keyword arguments that haven’t been filled in, and then call a function which dispatches on that. This approach is used e.g. here as part of the implementation for mapreduce.

julia> struct _EmptyArg end
       begin local z,Z = _EmptyArg(),_EmptyArg
           _f(a, b, (c, d, e), ::NTuple{3,Z}) = let x=(;c,d,e), ks=filter(k->x[k]!==z,keys(x)), vs=map(k->x[k],ks); f1(a, b; NamedTuple{ks}(vs)...) end
           _f(a, b, ::NTuple{3,Z}, (f, g, h)) = let x=(;f,g,h), ks=filter(k->x[k]!==z,keys(x)), vs=map(k->x[k],ks); f2(a, b; NamedTuple{ks}(vs)...) end
           f(a, b; c=z, d=z, e=z, f=z, g=z, h=z) = _f(a, b, (c, d, e), (f, g, h))
       end
       f1(a, b; c=1, d=2.0, e="hello") = "$a $b $c $d $e"
       f2(a, b; f="bye", g=π, h=nothing) = "$a $b $f $g $h";

julia> f(false,true; c=1//1)
"false true 1//1 2.0 hello"

julia> f(true,false; f="hi")
"true false hi π nothing"