# Add method with different arguments to existing function?

**URL:** <https://discourse.julialang.org/t/add-method-with-different-arguments-to-existing-function/96190>\
**Category:** New to Julia\
**Tags:** question, functions, multidispatch\
**Created:** [March 16, 2023, 3:17pm UTC](https://discourse.julialang.org/t/add-method-with-different-arguments-to-existing-function/96190 "2023-03-16T15:17:43Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![abehersan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abehersan/32/47221_2.png) [@abehersan](https://discourse.julialang.org/u/abehersan)\
**Post date:** [March 16, 2023, 3:17pm UTC](https://discourse.julialang.org/t/add-method-with-different-arguments-to-existing-function/96190/1 "2023-03-16T15:17:43Z")

</div>

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()`?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [March 16, 2023, 3:19pm UTC](https://discourse.julialang.org/t/add-method-with-different-arguments-to-existing-function/96190/2 "2023-03-16T15:19:21Z")

</div>

> [@abehersan](#):
>
> Is this possible without overwriting the first method for `f()`?

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

---

<div class="post-metadata">

**Author:** ![abehersan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abehersan/32/47221_2.png) [@abehersan](https://discourse.julialang.org/u/abehersan)\
**Post date:** [March 16, 2023, 3:29pm UTC](https://discourse.julialang.org/t/add-method-with-different-arguments-to-existing-function/96190/3 "2023-03-16T15:29:31Z")

</div>

I see, thanks for taking the time to answer!

---

<div class="post-metadata">

**Author:** ![Nathan\_Boyer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nathan_boyer/32/14825_2.png) [@Nathan\_Boyer](https://discourse.julialang.org/u/Nathan_Boyer)\
**Post date:** [March 16, 2023, 4:31pm UTC](https://discourse.julialang.org/t/add-method-with-different-arguments-to-existing-function/96190/4 "2023-03-16T16:31:06Z")

</div>

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
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
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`.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [March 17, 2023, 3:37am UTC](https://discourse.julialang.org/t/add-method-with-different-arguments-to-existing-function/96190/5 "2023-03-17T03:37:06Z")

</div>

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](https://github.com/JuliaLang/julia/blob/master/base/reduce.jl#L175) as part of the implementation for `mapreduce`.

```julia
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"

```

---

<div class="post-metadata">

**Author:** ![abehersan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abehersan/32/47221_2.png) [@abehersan](https://discourse.julialang.org/u/abehersan)\
**Post date:** [March 30, 2023, 11:51am UTC](https://discourse.julialang.org/t/add-method-with-different-arguments-to-existing-function/96190/6 "2023-03-30T11:51:15Z")

</div>

Thanks @uniment and @Nathan_Boyer for your answers!

While in principle dispatching over variable keyword arguments can be useful in some cases, I found that it can be avoided by simply relegating each combination of kwargs to its own function and then dispatching on those.

For my specific example I found that the code is more legible if one refrains from dispatching (or even splatting) kwargs.Many legible (and testable!!!) functions are better than a single function with a ton of kwargs that can vary.

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [March 31, 2023, 7:45am UTC](https://discourse.julialang.org/t/add-method-with-different-arguments-to-existing-function/96190/7 "2023-03-31T07:45:23Z")

</div>

if you can act on the original function, you can set it this way and then be able to add new methods with different kwargs

```julia

nt1=(; c=1, d=2.0, e="hello")

function f(a::Number, b::Number,nt :: typeof(nt1)) 
    println(nt.e, '\n', a+b, '\n', nt.c*nt.d)
end
f(3, 2 ,nt1)

nt2=(; f="bye", g=pi, h=nothing)

function f(a::Number, b::Number, nt::typeof(nt2))
    println(nt.f, '\n', a+b, '\n', isnothing(nt.h) ? 2*nt.g : nt.g/2)
end
f(3, 2, nt2)

```

PS  
I’m not very confident that what has been proposed above makes much sense, in general.

Edit: Can someone of good will and good knowledge explain why it doesn’t work

```julia

julia> nt2=NamedTuple{(:f, :g, :h), Tuple{String, Irrational{:π}, Any}}((f="bye", g=pi, h=nothing))
NamedTuple{(:f, :g, :h), Tuple{String, Irrational{:π}, Any}}(("bye", π, nothing))

julia> function f(a::Number, b::Number, nt::typeof(nt2))
           println(nt.f, '\n', a+b, '\n', isnothing(nt.h) ? 2*nt.g : nt.g/2)
       end
f (generic function with 1 method)

julia> f(3, 2, nt2)
bye
5
6.283185307179586

julia> Tuple{String, Irrational{:π}, Nothing} <: Tuple{String, Irrational{:π}, Any}
true

julia> Tuple{String, Irrational{:π}, Number} <: Tuple{String, Irrational{:π}, Any}
true

julia> nt=merge(nt2, (f="addio",h=9))
(f = "addio", g = π, h = 9)

julia> f(5,4,nt)
ERROR: MethodError: no method matching f(::Int64, ::Int64, ::NamedTuple{(:f, :g, :h), Tuple{String, Irrational{:π}, Int64}})
Closest candidates are:
  f(::Number, ::Number, ::NamedTuple{(:f, :g, :h), Tuple{String, Irrational{:π}, Any}}) at c:\Users\sprmn\.julia\environments\v1.8.3\functions2.jl:88
Stacktrace:
 [1] top-level scope
   @ c:\Users\sprmn\.julia\environments\v1.8.3\functions2.jl:100

```

Is it possible to have a NamedTuple as a subtype of a more generic namedtuple?
