# Methods of a function that has both optional positional argument and keyword argument

**URL:** <https://discourse.julialang.org/t/methods-of-a-function-that-has-both-optional-positional-argument-and-keyword-argument/78869>\
**Category:** General Usage\
**Tags:** argument, dispatch, function\
**Created:** [April 1, 2022, 1:40pm UTC](https://discourse.julialang.org/t/methods-of-a-function-that-has-both-optional-positional-argument-and-keyword-argument/78869 "2022-04-01T13:40:05Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![frankwswang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/frankwswang/32/18561_2.png) [@frankwswang](https://discourse.julialang.org/u/frankwswang)\
**Post date:** [April 1, 2022, 1:40pm UTC](https://discourse.julialang.org/t/methods-of-a-function-that-has-both-optional-positional-argument-and-keyword-argument/78869/1 "2022-04-01T13:40:05Z")

</div>

I know keyword arguments don’t invoke multiple dispatch. So methods with the same positional arguments except keyword arguments can overload each other:

```julia
julia> f(a) = a
f (generic function with 1 method)

julia> methods(f)
# 1 method for generic function "f":
[1] f(a) in Main at REPL[1]:1

julia> f(a; b) = a+b
f (generic function with 1 method)

julia> methods(f)
# 1 method for generic function "f":
[1] f(a; b) in Main at REPL[2]:1

```

However, I found that when the defined function has optional positional arguments, only the method with no positional arguments omitted keeps the keyword argument:

```julia
julia> h(a, b=1, c=2; d) = a+b+c+d
h (generic function with 3 methods)

julia> methods(h)
# 3 methods for generic function "h":
[1] h(a) in Main at REPL[6]:1 # Why not h(a; d)?
[2] h(a, b) in Main at REPL[6]:1 # Why not h(a, b; d)?
[3] h(a, b, c; d) in Main at REPL[6]:1

```

Is there a particular reason for this design? I thought keeping the keyword argument in the method definition is a more intuitive decision but maybe there’s some good explanation I don’t know. Thanks a lot!

---

<div class="post-metadata">

**Author:** ![Liozou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/liozou/32/35118_2.png) [@Liozou](https://discourse.julialang.org/u/Liozou)\
**Post date:** [April 1, 2022, 2:11pm UTC](https://discourse.julialang.org/t/methods-of-a-function-that-has-both-optional-positional-argument-and-keyword-argument/78869/2 "2022-04-01T14:11:29Z")

</div>

I think you might find some explanation in the devdocs, specifically the section on keyword arguments: [Julia Functions · The Julia Language](https://docs.julialang.org/en/v1/devdocs/functions/#Keyword-arguments)

Tangentially, you might be interested in my recent PR [#44434](https://github.com/JuliaLang/julia/pull/44434) which hides this internal design in the display of `methods(h)`.

---

<div class="post-metadata">

**Author:** ![frankwswang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/frankwswang/32/18561_2.png) [@frankwswang](https://discourse.julialang.org/u/frankwswang)\
**Post date:** [April 2, 2022, 12:27am UTC](https://discourse.julialang.org/t/methods-of-a-function-that-has-both-optional-positional-argument-and-keyword-argument/78869/3 "2022-04-02T00:27:54Z")

</div>

Thanks! I’ll look into them.

---

<div class="post-metadata">

**Author:** ![frankwswang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/frankwswang/32/18561_2.png) [@frankwswang](https://discourse.julialang.org/u/frankwswang)\
**Post date:** [April 2, 2022, 1:27pm UTC](https://discourse.julialang.org/t/methods-of-a-function-that-has-both-optional-positional-argument-and-keyword-argument/78869/4 "2022-04-02T13:27:14Z")

</div>

I think there’s a bug either with the print info or the method dispatch:

```julia
julia> f1(;k=1) = k
f1 (generic function with 1 method)

julia> methods(f1)
# 1 method for generic function "f1":
[1] f1(; k) in Main at REPL[24]:1

julia> f2() = 0
f2 (generic function with 1 method)

julia> methods(f2)
# 1 method for generic function "f2":
[1] f2() in Main at REPL[26]:1

julia> f3(a=0;k=1) = a+k
f3 (generic function with 2 methods)

julia> methods(f3)
# 2 methods for generic function "f3":
[1] f3() in Main at REPL[28]:1
[2] f3(a; k) in Main at REPL[28]:1

julia> f3()
1

julia> f3(k=3)
3

```

In the print info, it shows that the method of `f3` which has no positional arguments should also not accept the keyword argument `k`, but in reality, it can accept it.

---

<div class="post-metadata">

**Author:** ![frankwswang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/frankwswang/32/18561_2.png) [@frankwswang](https://discourse.julialang.org/u/frankwswang)\
**Post date:** [April 2, 2022, 1:59pm UTC](https://discourse.julialang.org/t/methods-of-a-function-that-has-both-optional-positional-argument-and-keyword-argument/78869/5 "2022-04-02T13:59:36Z")

</div>

Then if I overload the method of `f()`, I can’t really eliminate the keyword argument:

```julia
julia> f3() = NaN
f3 (generic function with 2 methods)

julia> f3()
NaN

julia> f3(k=3)
3

```

Does this mean there’s no way to remove the keyword arguments from a predefined function through overloading?

---

<div class="post-metadata">

**Author:** ![Liozou](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/liozou/32/35118_2.png) [@Liozou](https://discourse.julialang.org/u/Liozou)\
**Post date:** [April 7, 2022, 1:03pm UTC](https://discourse.julialang.org/t/methods-of-a-function-that-has-both-optional-positional-argument-and-keyword-argument/78869/6 "2022-04-07T13:03:50Z")

</div>

There is no bug really, it’s just the same issue as in your first message, which boils down to the fact that the printing of `methods(f)` is misleading when `f` has keyword and optional arguments. You can have a look at `methods(methods(f3).mt.kwsorter)` if you’re interested in checking which methods exist and will actually be called when doing a function call of `f3` with a keyword argument (but having a read of the devdocs I mentioned is probably necessary to understand what this is all about).

To answer the second question, there is indeed no way (that I can think of) to remove a keyword argument. Note that there is no way to remove a positional argument either actually, and it comes from the fact that there is no way to remove a method, period. But you can replace a method by defining another with the same argument types and keyword argument names: that’s not really overloading but more shadowing I’d say. And you can of course add other methods to tweak the behavior depending on the number and types of the arguments and the names of the keyword arguments, for instance by doing `f3(; k) = k-12` or `f3(a; k) = 2a-k`. That’s regular multiple dispatch.

Issue [#9498](https://github.com/JuliaLang/julia/issues/9498#issuecomment-504363878) might interest you regarding all this: as you can see there are some known trick cases relating to method definitions with keyword arguments.

---

<div class="post-metadata">

**Author:** ![frankwswang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/frankwswang/32/18561_2.png) [@frankwswang](https://discourse.julialang.org/u/frankwswang)\
**Post date:** [April 7, 2022, 1:45pm UTC](https://discourse.julialang.org/t/methods-of-a-function-that-has-both-optional-positional-argument-and-keyword-argument/78869/7 "2022-04-07T13:45:41Z")

</div>

Thanks for the reply again. The issue threads you provided (including the previous one) are all very helpful! The print info for `methods` can definitely be improved. As for the dispatch when involving optional keyword arguments, It seems that people have been discussing this bizarre consequence, if not considered a bug, for quite a while. In my opinion, the methods that have the exact same positional arguments except the optional keyword argument should be able to shadow each other, not just one way. So I hope the inconsistency shown in [#9498](https://github.com/JuliaLang/julia/issues/9498#issuecomment-504363878) can be resolved in the near future. Personally, I feel like missing the multiple dispatch support for keyword arguments alone is what really makes the whole situation a bit messy.
