<p dir="auto">This is a reduced version of the issue raised at <a href="https://discourse.julialang.org/t/type-unstable-keyword-constructor-on-parameterized-type/8852" rel="nofollow">https://discourse.julialang.org/t/type-unstable-keyword-constructor-on-parameterized-type/8852</a></p>
<p dir="auto">I think its a bug, but I could be wrong.</p>
<p dir="auto">Basically, the presence of (even unused) keyword args in an inner constructor spoils type-stability.</p>
<p dir="auto">On 0.6.1</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="julia&gt; struct Foo
           Foo(; kwargs...) = new()
       end

julia&gt; @code_warntype Foo()
Variables:
  #self#::Type{Foo}

Body:
  begin 
      return ((Core.getfield)($(QuoteNode(Core.Box(#call#1))), :contents)::Any)($(Expr(:foreigncall, :(:jl_alloc_array_1d), Array{Any,1}, svec(Any, Int64), Array{Any,1}, 0, 0, 0)), #self#::Type{Foo})::Any
  end::Any"><pre class="notranslate">julia<span class="pl-k">&gt;</span> <span class="pl-k">struct</span> Foo
           <span class="pl-en">Foo</span>(; kwargs<span class="pl-k">...</span>) <span class="pl-k">=</span> <span class="pl-c1">new</span>()
       <span class="pl-k">end</span>

julia<span class="pl-k">&gt;</span> <span class="pl-c1">@code_warntype</span> <span class="pl-c1">Foo</span>()
Variables<span class="pl-k">:</span>
  <span class="pl-c"><span class="pl-c">#</span>self#::Type{Foo}</span>

Body<span class="pl-k">:</span>
  <span class="pl-k">begin</span> 
      <span class="pl-k">return</span> ((Core<span class="pl-k">.</span>getfield)(<span class="pl-k">$</span>(<span class="pl-c1">QuoteNode</span>(Core<span class="pl-k">.</span><span class="pl-c1">Box</span>(<span class="pl-c"><span class="pl-c">#</span>call#1))), :contents)::Any)($(Expr(:foreigncall, :(:jl_alloc_array_1d), Array{Any,1}, svec(Any, Int64), Array{Any,1}, 0, 0, 0)), #self#::Type{Foo})::Any</span>
  <span class="pl-k">end</span><span class="pl-k">::</span><span class="pl-c1">Any</span></pre></div>
<p dir="auto">and current master (<a class="commit-link" data-hovercard-type="commit" data-hovercard-url="https://github.com/JuliaLang/julia/commit/251a501def6a52d497784ad1ca8206579d814bce/hovercard" href="https://github.com/JuliaLang/julia/commit/251a501def6a52d497784ad1ca8206579d814bce"><tt>251a501</tt></a>)</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="julia&gt; struct Foo
           Foo(; kwargs...) = new()
       end

julia&gt; @code_warntype Foo()
Variables:
  #self#::Type{Foo}
  #Foo#1@_3::Nothing

Body:
  begin
      Core.SSAValue(0) = $(QuoteNode(Core.Box(getfield(, Symbol(&quot;##Foo#1#2&quot;))())))
      Core.SSAValue(1) = (Core.isdefined)(Core.SSAValue(0), :contents)::Bool
      unless Core.SSAValue(1) goto 5
      goto 8
      5: 
      Core.NewvarNode(:(#Foo#1@_3::Nothing))
      #Foo#1@_3::Nothing
      8: 
      Core.SSAValue(2) = (Core.getfield)(Core.SSAValue(0), :contents)::Any
      Core.SSAValue(5) = (Core.SSAValue(2))($(QuoteNode(Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}())), #self#::Type{Foo})::Any
      return Core.SSAValue(5)
  end::Any

"><pre class="notranslate">julia<span class="pl-k">&gt;</span> <span class="pl-k">struct</span> Foo
           <span class="pl-en">Foo</span>(; kwargs<span class="pl-k">...</span>) <span class="pl-k">=</span> <span class="pl-c1">new</span>()
       <span class="pl-k">end</span>

julia<span class="pl-k">&gt;</span> <span class="pl-c1">@code_warntype</span> <span class="pl-c1">Foo</span>()
Variables<span class="pl-k">:</span>
  <span class="pl-c"><span class="pl-c">#</span>self#::Type{Foo}</span>
  <span class="pl-c"><span class="pl-c">#</span>Foo#1@_3::Nothing</span>

Body<span class="pl-k">:</span>
  <span class="pl-k">begin</span>
      Core<span class="pl-k">.</span><span class="pl-en">SSAValue</span>(<span class="pl-c1">0</span>) <span class="pl-k">=</span> <span class="pl-k">$</span>(<span class="pl-c1">QuoteNode</span>(Core<span class="pl-k">.</span><span class="pl-c1">Box</span>(<span class="pl-c1">getfield</span>(, <span class="pl-c1">Symbol</span>(<span class="pl-s"><span class="pl-pds">"</span>##Foo#1#2<span class="pl-pds">"</span></span>))())))
      Core<span class="pl-k">.</span><span class="pl-en">SSAValue</span>(<span class="pl-c1">1</span>) <span class="pl-k">=</span> (Core<span class="pl-k">.</span>isdefined)(Core<span class="pl-k">.</span><span class="pl-c1">SSAValue</span>(<span class="pl-c1">0</span>), <span class="pl-c1">:contents</span>)<span class="pl-k">::</span><span class="pl-c1">Bool</span>
      unless Core<span class="pl-k">.</span><span class="pl-c1">SSAValue</span>(<span class="pl-c1">1</span>) goto <span class="pl-c1">5</span>
      goto <span class="pl-c1">8</span>
      <span class="pl-c1">5</span><span class="pl-k">:</span> 
      Core<span class="pl-k">.</span><span class="pl-c1">NewvarNode</span>(:(<span class="pl-c"><span class="pl-c">#</span>Foo#1@_3::Nothing))</span>
      <span class="pl-c"><span class="pl-c">#</span>Foo#1@_3::Nothing</span>
      <span class="pl-c1">8</span><span class="pl-k">:</span> 
      Core<span class="pl-k">.</span><span class="pl-en">SSAValue</span>(<span class="pl-c1">2</span>) <span class="pl-k">=</span> (Core<span class="pl-k">.</span>getfield)(Core<span class="pl-k">.</span><span class="pl-c1">SSAValue</span>(<span class="pl-c1">0</span>), <span class="pl-c1">:contents</span>)<span class="pl-k">::</span><span class="pl-c1">Any</span>
      Core<span class="pl-k">.</span><span class="pl-en">SSAValue</span>(<span class="pl-c1">5</span>) <span class="pl-k">=</span> (Core<span class="pl-k">.</span><span class="pl-c1">SSAValue</span>(<span class="pl-c1">2</span>))(<span class="pl-k">$</span>(<span class="pl-c1">QuoteNode</span>(Base<span class="pl-k">.</span>Iterators<span class="pl-k">.</span><span class="pl-c1">Pairs</span><span class="pl-c1">{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}</span>())), <span class="pl-c"><span class="pl-c">#</span>self#::Type{Foo})::Any</span>
      <span class="pl-k">return</span> Core<span class="pl-k">.</span><span class="pl-c1">SSAValue</span>(<span class="pl-c1">5</span>)
  <span class="pl-k">end</span><span class="pl-k">::</span><span class="pl-c1">Any</span>

</pre></div>
<p dir="auto">I find constructors taking keyword arguments are a lot slower than constructors that don't.  For example,</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="julia&gt; immutable PositionalArg
           x::Int
           PositionalArg(x::Int=1) = new(x)
       end

julia&gt; immutable KeywordArg
           x::Int
           KeywordArg(;x::Int=1) = new(x)
       end

julia&gt; using BenchmarkTools

julia&gt; @benchmark PositionalArg()
BenchmarkTools.Trial:
  memory estimate:  0.00 bytes
  allocs estimate:  0
  --------------
  minimum time:     2.087 ns (0.00% GC)
  median time:      2.092 ns (0.00% GC)
  mean time:        2.381 ns (0.00% GC)
  maximum time:     386.548 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     1000
  time tolerance:   5.00%
  memory tolerance: 1.00%

julia&gt; @benchmark KeywordArg()
BenchmarkTools.Trial:
  memory estimate:  16.00 bytes
  allocs estimate:  1
  --------------
  minimum time:     75.253 ns (0.00% GC)
  median time:      78.912 ns (0.00% GC)
  mean time:        101.540 ns (1.62% GC)
  maximum time:     26.617 μs (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     970
  time tolerance:   5.00%
  memory tolerance: 1.00%"><pre class="notranslate"><code class="notranslate">julia&gt; immutable PositionalArg
           x::Int
           PositionalArg(x::Int=1) = new(x)
       end

julia&gt; immutable KeywordArg
           x::Int
           KeywordArg(;x::Int=1) = new(x)
       end

julia&gt; using BenchmarkTools

julia&gt; @benchmark PositionalArg()
BenchmarkTools.Trial:
  memory estimate:  0.00 bytes
  allocs estimate:  0
  --------------
  minimum time:     2.087 ns (0.00% GC)
  median time:      2.092 ns (0.00% GC)
  mean time:        2.381 ns (0.00% GC)
  maximum time:     386.548 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     1000
  time tolerance:   5.00%
  memory tolerance: 1.00%

julia&gt; @benchmark KeywordArg()
BenchmarkTools.Trial:
  memory estimate:  16.00 bytes
  allocs estimate:  1
  --------------
  minimum time:     75.253 ns (0.00% GC)
  median time:      78.912 ns (0.00% GC)
  mean time:        101.540 ns (1.62% GC)
  maximum time:     26.617 μs (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     970
  time tolerance:   5.00%
  memory tolerance: 1.00%
</code></pre></div>
<p dir="auto">Such a huge difference seems to be caused by the additional allocations that constructors with keyword arguments use.  However, I'm not sure if that has to be the case, because ordinary functions don't seem to be using additional allocations when taking keyword arguments:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="julia&gt; posarg(x::Int=1) = x
posarg (generic function with 2 methods)

julia&gt; kwdarg(;x::Int=1) = x
kwdarg (generic function with 1 method)

julia&gt; @benchmark posarg()
BenchmarkTools.Trial:
  memory estimate:  0.00 bytes
  allocs estimate:  0
  --------------
  minimum time:     1.997 ns (0.00% GC)
  median time:      1.998 ns (0.00% GC)
  mean time:        2.282 ns (0.00% GC)
  maximum time:     95.239 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     1000
  time tolerance:   5.00%
  memory tolerance: 1.00%

julia&gt; @benchmark kwdarg()
BenchmarkTools.Trial:
  memory estimate:  0.00 bytes
  allocs estimate:  0
  --------------
  minimum time:     1.997 ns (0.00% GC)
  median time:      1.998 ns (0.00% GC)
  mean time:        2.042 ns (0.00% GC)
  maximum time:     273.882 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     1000
  time tolerance:   5.00%
  memory tolerance: 1.00%"><pre class="notranslate"><code class="notranslate">julia&gt; posarg(x::Int=1) = x
posarg (generic function with 2 methods)

julia&gt; kwdarg(;x::Int=1) = x
kwdarg (generic function with 1 method)

julia&gt; @benchmark posarg()
BenchmarkTools.Trial:
  memory estimate:  0.00 bytes
  allocs estimate:  0
  --------------
  minimum time:     1.997 ns (0.00% GC)
  median time:      1.998 ns (0.00% GC)
  mean time:        2.282 ns (0.00% GC)
  maximum time:     95.239 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     1000
  time tolerance:   5.00%
  memory tolerance: 1.00%

julia&gt; @benchmark kwdarg()
BenchmarkTools.Trial:
  memory estimate:  0.00 bytes
  allocs estimate:  0
  --------------
  minimum time:     1.997 ns (0.00% GC)
  median time:      1.998 ns (0.00% GC)
  mean time:        2.042 ns (0.00% GC)
  maximum time:     273.882 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     1000
  time tolerance:   5.00%
  memory tolerance: 1.00%
</code></pre></div>
<p dir="auto">Is this a matter that can be fixed easily, or I need to refrain from using keyword arguments in constructors?</p>
<p dir="auto">Here is the version info:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="julia&gt; versioninfo()
Julia Version 0.6.0-dev.1636
Commit 99b6a8c* (2016-12-20 13:46 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin16.0.0)
  CPU: Intel(R) Core(TM)2 Duo CPU     T9900  @ 3.06GHz
  WORD_SIZE: 64
  BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Penryn)
  LAPACK: libopenblas64_
  LIBM: libopenlibm
  LLVM: libLLVM-3.7.1 (ORCJIT, penryn)"><pre class="notranslate"><code class="notranslate">julia&gt; versioninfo()
Julia Version 0.6.0-dev.1636
Commit 99b6a8c* (2016-12-20 13:46 UTC)
Platform Info:
  OS: macOS (x86_64-apple-darwin16.0.0)
  CPU: Intel(R) Core(TM)2 Duo CPU     T9900  @ 3.06GHz
  WORD_SIZE: 64
  BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Penryn)
  LAPACK: libopenblas64_
  LIBM: libopenlibm
  LLVM: libLLVM-3.7.1 (ORCJIT, penryn)
</code></pre></div>