# Keyword argument constructor breaks Incomplete constructor

**URL:** <https://discourse.julialang.org/t/keyword-argument-constructor-breaks-incomplete-constructor/34198>\
**Category:** General Usage\
**Created:** [February 5, 2020, 5:35am UTC](https://discourse.julialang.org/t/keyword-argument-constructor-breaks-incomplete-constructor/34198 "2020-02-05T05:35:31Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![milesf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milesf/32/9289_2.png) [@milesf](https://discourse.julialang.org/u/milesf)\
**Post date:** [February 5, 2020, 5:35am UTC](https://discourse.julialang.org/t/keyword-argument-constructor-breaks-incomplete-constructor/34198/1 "2020-02-05T05:35:31Z")

</div>

```julia
julia> mutable struct Foo
           x::Float64
           y::Float64

           Foo() = new()
           Foo(;x::Float64, y::Float64) = new(x, y)
       end

julia> Foo()
ERROR: UndefKeywordError: keyword argument x not assigned

```

Removing the keyword constructor allows calling the [incomplete constructor](https://docs.julialang.org/en/v1/manual/constructors/#Incomplete-Initialization-1).

```julia
julia> mutable struct Bar
           x::Float64
           y::Float64

           Bar() = new()
       end

julia> Bar()
Bar(6.94551551140594e-310, 5.0e-324)

```

Is there a way to have both the full keyword constructor and the incomplete constructor?

---

<div class="post-metadata">

**Author:** ![milesf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milesf/32/9289_2.png) [@milesf](https://discourse.julialang.org/u/milesf)\
**Post date:** [February 5, 2020, 5:47am UTC](https://discourse.julialang.org/t/keyword-argument-constructor-breaks-incomplete-constructor/34198/2 "2020-02-05T05:47:08Z")

</div>

Interesting! It works if the keyword constructor is defined first:

```julia
julia> mutable struct Foo
           x::Float64
           y::Float64

           Foo(;x::Float64, y::Float64) = new(x, y)
           Foo() = new()
       end

julia> Foo()
Foo(6.94551569230195e-310, 0.0)

```

Looks like this gotcha was already reported here:

> [@Fun with kwargs methods](https://discourse.julialang.org/t/fun-with-kwargs-methods/15711/7):
>
> zerosM(dim; like::AbstractArray=Vector{Float64}()) = zeros(eltype(like), dim, dim) should do what you want.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 5, 2020, 6:53am UTC](https://discourse.julialang.org/t/keyword-argument-constructor-breaks-incomplete-constructor/34198/3 "2020-02-05T06:53:12Z")

</div>

You just ovewriting that method. Cf

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

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

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

julia> f()
(1, 2)

```

How could the language distinguish the first one from the second called without any keyword arguments?

---

<div class="post-metadata">

**Author:** ![milesf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milesf/32/9289_2.png) [@milesf](https://discourse.julialang.org/u/milesf)\
**Post date:** [February 5, 2020, 8:14pm UTC](https://discourse.julialang.org/t/keyword-argument-constructor-breaks-incomplete-constructor/34198/4 "2020-02-05T20:14:19Z")

</div>

I understand how your example with only **optional** keyword arguments is indistinguishable from no arguments.

But I expect the language to distinguish between a method that accepts zero arguments and a method that accepts two **mandatory** keyword arguments.

The language can distinguish between these methods, but only if they are defined in a special sequence. It’s confusing why `methods` still displays the same output, even though the method was either modified to accept different arguments or a new method was added. It would be helpful for `methods` to show whether the keyword arguments are optional or mandatory.

```julia
# ------ working sequence ----------

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[1]:1

julia> f() = 5
f (generic function with 1 method)

# "overwritten" method looks the same as before, but now also supports zero arguments.

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

# support for no-arguments and mandatory keyword arguments

julia> f()
5

julia> f(a=1, b=2)
3

# ------------ failing sequence ----------------

julia> g() = 5
g (generic function with 1 method)

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

# adding support for mandatory keyword arguments afterwards breaks support for no arguments

julia> g()
ERROR: UndefKeywordError: keyword argument a not assigned
Stacktrace:
 [1] g() at ./REPL[10]:1
 [2] top-level scope at REPL[11]:1

```

---

<div class="post-metadata">

**Author:** ![tbeason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tbeason/32/15898_2.png) [@tbeason](https://discourse.julialang.org/u/tbeason)\
**Post date:** [February 5, 2020, 8:34pm UTC](https://discourse.julialang.org/t/keyword-argument-constructor-breaks-incomplete-constructor/34198/5 "2020-02-05T20:34:17Z")

</div>

I’ve not seen mandatory keyword arguments before, and it seems to me like they should just be positional arguments. Then you have no issues, yes?

I know this is not helpful for your question.

EDIT: Well I guess there were some methods (eg. `sum`) that did start forcing me to supply `dims` …

---

<div class="post-metadata">

**Author:** ![milesf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milesf/32/9289_2.png) [@milesf](https://discourse.julialang.org/u/milesf)\
**Post date:** [February 5, 2020, 8:48pm UTC](https://discourse.julialang.org/t/keyword-argument-constructor-breaks-incomplete-constructor/34198/6 "2020-02-05T20:48:38Z")

</div>

> [@tbeason](#):
>
> it seems to me like they should just be positional arguments

I like to use mandatory keyword arguments instead of positional arguments to avoid bugs when calling constructors of large structs. It’s easy to mess-up the sequence of arguments, and there are no obvious errors if the swapped arguments share the same type. This also helps catch any bugs after adding/removing/reorganizing fields of a struct.

Are there other recommendations for avoiding these types of bugs?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 6, 2020, 8:07am UTC](https://discourse.julialang.org/t/keyword-argument-constructor-breaks-incomplete-constructor/34198/7 "2020-02-06T08:07:12Z")

</div>

> [@milesf](#):
>
> I expect the language to distinguish between a method that accepts zero arguments and a method that accepts two **mandatory** keyword arguments

Keyword arguments [don’t participate in dispatch](https://docs.julialang.org/en/v1/manual/methods/#Note-on-Optional-and-keyword-Arguments-1) (on the surface, the internal implementation is another thing, see below).

> [@milesf](#):
>
> The language can distinguish between these methods, but only if they are defined in a special sequence.

This is a quirk of the [implementation](https://docs.julialang.org/en/v1/devdocs/functions/#Keyword-arguments-1) — you are overwriting one of the three functions mentioned there. It is a known issue, see

> <https://github.com/JuliaLang/julia/issues/9498#issuecomment-504363878>
>
> So this is an issue that I find after figuring out how the keyword arguments are… currently implemented in Julia. It will probably not be an issue anymore if #2773 is implemented.
> 
> The document on methods says
> 
> \> Methods are dispatched based only on positional arguments, with keyword arguments processed after the matching method is identified.
> 
> However, method dispatch actually behaves differently when doing a function call with or without keyword arguments. i.e.
> 
> \`\`\` julia
> julia\> function f(::Integer)
> 2
> end
> f (generic function with 1 method)
> 
> julia\> function f(::Number; kw...)
> 1
> end
> f (generic function with 2 methods)
> 
> julia\> f(1)
> 2
> 
> julia\> f(1; a = 2)
> 1
> \`\`\`
> 
> What happens here is that \`f.env.kwsorter\` only has one method defined and therefore when calling with keyword argument, \`f(::Integer)\` does not participate in method dispatch.
> 
> IMHO, there are several possible ways to fix it,
> 1. Fix the document to include this behavior. This should be the easiest fix but will probably make the whole keyword argument/optional argument/multiple dispatch more confusing especially for someone who does not know how it all works behind the scene. (It's already quite confusing/surprising that anonymous function does not support keyword argument for someone (like me) that expects python-like keyword argument implementation.)
> 2. Having an entry (that just throw an error) in \`env.kwsorter\` even for methods that does not take keyword arguments. This can also avoid the following confusing abuse of overriding method
>    
> \`\`\` julia
> julia\> function f(::Number; kw...)
> 1
> end
> f (generic function with 1 method)
>    
> julia\> function f(::Number)
> 2
> end
> f (generic function with 1 method)
>    
> julia\> f(1)
> 2
>    
> julia\> f(1; a = 2)
> 1
> \`\`\`
>    
> This is probably the easiest way to fix the code and is consistent with the best long term behavior.
> 3. Fix #2773 and let the method themselves handle keyword argument dispatch. Since #2773 is on \`1.0\` milestone, hopefully this will be eventually be implemented.

Just don’t rely on this.
