<p dir="auto">This might just be <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="341348846" data-permission-text="Title is private" data-url="https://github.com/JuliaLang/julia/issues/28126" data-hovercard-type="issue" data-hovercard-url="/JuliaLang/julia/issues/28126/hovercard" href="https://github.com/JuliaLang/julia/issues/28126">#28126</a>, but it looks like a separate problem. On 1.0.2:</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="julia&gt; using BenchmarkTools

julia&gt; v = fill(2.0, 50000);

julia&gt; v2 = vcat(v, missing);

julia&gt; v3 = vcat(missing, v);

julia&gt; @btime $v .* 3.0;
  33.105 μs (2 allocations: 390.70 KiB)

julia&gt; @btime $v2 .* 3.0;
  1.610 ms (99498 allocations: 2.33 MiB)

julia&gt; @btime $v3 .* 3.0;
  3.867 ms (7 allocations: 439.77 KiB)"><pre class="notranslate">julia<span class="pl-k">&gt;</span> <span class="pl-k">using</span> BenchmarkTools

julia<span class="pl-k">&gt;</span> v <span class="pl-k">=</span> <span class="pl-c1">fill</span>(<span class="pl-c1">2.0</span>, <span class="pl-c1">50000</span>);

julia<span class="pl-k">&gt;</span> v2 <span class="pl-k">=</span> <span class="pl-c1">vcat</span>(v, <span class="pl-c1">missing</span>);

julia<span class="pl-k">&gt;</span> v3 <span class="pl-k">=</span> <span class="pl-c1">vcat</span>(<span class="pl-c1">missing</span>, v);

julia<span class="pl-k">&gt;</span> <span class="pl-c1">@btime</span> <span class="pl-k">$</span>v <span class="pl-k">.*</span> <span class="pl-c1">3.0</span>;
  <span class="pl-c1">33.105</span> μs (<span class="pl-c1">2</span> allocations<span class="pl-k">:</span> <span class="pl-c1">390.70</span> KiB)

julia<span class="pl-k">&gt;</span> <span class="pl-c1">@btime</span> <span class="pl-k">$</span>v2 <span class="pl-k">.*</span> <span class="pl-c1">3.0</span>;
  <span class="pl-c1">1.610</span> ms (<span class="pl-c1">99498</span> allocations<span class="pl-k">:</span> <span class="pl-c1">2.33</span> MiB)

julia<span class="pl-k">&gt;</span> <span class="pl-c1">@btime</span> <span class="pl-k">$</span>v3 <span class="pl-k">.*</span> <span class="pl-c1">3.0</span>;
  <span class="pl-c1">3.867</span> ms (<span class="pl-c1">7</span> allocations<span class="pl-k">:</span> <span class="pl-c1">439.77</span> KiB)</pre></div>
<p dir="auto">Apart from the 40X performance difference, two things stand out:</p>
<ul dir="auto">
<li>99498 allocations for <code class="notranslate">v2</code>. Why?</li>
<li>Why is <code class="notranslate">v3</code> slower than <code class="notranslate">v2</code>, in spite of allocating much less?</li>
</ul>
<p dir="auto">I have been trying to get into using <code class="notranslate">missing</code> and fast <code class="notranslate">Union</code> types in my worflow and seem to be coming up with some issues. It's most easily highlighted by:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="julia&gt; @code_warntype [1, 2] + [3.0, missing]
Body::Array
44 1 ── %1  = (Base.getfield)(Bs, 1, true)::Array{Union{Missing, Float64},1}                                                                               │╻╷╷         iterate
   └───       goto #7 if not true                                                                                                                          │           
   2 ┄─ %3  = φ (#1 =&gt; %1, #6 =&gt; %12)::Array{Union{Missing, Float64},1}                                                                                    │           
   │    %4  = φ (#1 =&gt; 2, #6 =&gt; %13)::Int64                                                                                                                │           
45 │          invoke Base.promote_shape(_2::Array{Int64,1}, %3::Array{Union{Missing, Float64},1})                                                          │           
   │    %6  = (Base.slt_int)(1, %4)::Bool                                                                                                                  ││╻           &lt;
   └───       goto #4 if not %6                                                                                                                            ││          
   3 ──       goto #5                                                                                                                                      ││          
   4 ── %9  = (Base.getfield)(Bs, %4, true)::Array{Union{Missing, Float64},1}                                                                              ││╻           getindex
   │    %10 = (Base.add_int)(%4, 1)::Int64                                                                                                                 ││╻           +
   └───       goto #5                                                                                                                                      ││          
   5 ┄─ %12 = φ (#4 =&gt; %9)::Array{Union{Missing, Float64},1}                                                                                               │           
   │    %13 = φ (#4 =&gt; %10)::Int64                                                                                                                         │           
   │    %14 = φ (#3 =&gt; true, #4 =&gt; false)::Bool                                                                                                            │           
   │    %15 = (Base.not_int)(%14)::Bool                                                                                                                    │           
   └───       goto #7 if not %15                                                                                                                           │           
   6 ──       goto #2                                                                                                                                      │           
47 7 ── %18 = (getfield)(Bs, 1)::Array{Union{Missing, Float64},1}                                                                                          │           
   │    %19 = (Core.tuple)(A, %18)::Tuple{Array{Int64,1},Array{Union{Missing, Float64},1}}                                                                 ││╻           broadcasted
   │    %20 = (Base.arraysize)(A, 1)::Int64                                                                                                                │││╻╷╷╷╷       instantiate
   │    %21 = (Base.slt_int)(%20, 0)::Bool                                                                                                                 ││││╻╷╷╷        combine_axes
   │    %22 = (Base.ifelse)(%21, 0, %20)::Int64                                                                                                            │││││┃│││││      broadcast_axes
   │    %23 = %new(Base.OneTo{Int64}, %22)::Base.OneTo{Int64}                                                                                              ││││││┃│││        axes
   │    %24 = (Base.arraysize)(%18, 1)::Int64                                                                                                              ││││││╻╷╷         broadcast_axes
   │    %25 = (Base.slt_int)(%24, 0)::Bool                                                                                                                 │││││││╻╷╷╷        axes
   │    %26 = (Base.ifelse)(%25, 0, %24)::Int64                                                                                                            ││││││││┃│││        map
   │    %27 = %new(Base.OneTo{Int64}, %26)::Base.OneTo{Int64}                                                                                              │││││││││┃│          Type
   │    %28 = (%26 === %22)::Bool                                                                                                                          ││││││╻╷╷╷╷       _bcs
   │    %29 = (Base.and_int)(true, %28)::Bool                                                                                                              │││││││╻           _bcs1
   └───       goto #9 if not %29                                                                                                                           ││││││││┃           _bcsm
   8 ──       goto #10                                                                                                                                     │││││││││   
   9 ── %32 = (%22 === 1)::Bool                                                                                                                            │││││││││╻           ==
   └───       goto #10                                                                                                                                     │││││││││   
   10 ┄ %34 = φ (#8 =&gt; %29, #9 =&gt; %32)::Bool                                                                                                               ││││││││    
   └───       goto #12 if not %34                                                                                                                          ││││││││    
   11 ─       goto #18                                                                                                                                     ││││││││    
   12 ─ %37 = (%22 === %26)::Bool                                                                                                                          │││││││││╻╷          ==
   │    %38 = (Base.and_int)(true, %37)::Bool                                                                                                              ││││││││││╻           &amp;
   └───       goto #14 if not %38                                                                                                                          │││││││││   
   13 ─       goto #15                                                                                                                                     │││││││││   
   14 ─ %41 = (%26 === 1)::Bool                                                                                                                            │││││││││╻           ==
   └───       goto #15                                                                                                                                     │││││││││   
   15 ┄ %43 = φ (#13 =&gt; %38, #14 =&gt; %41)::Bool                                                                                                             ││││││││    
   └───       goto #17 if not %43                                                                                                                          ││││││││    
   16 ─       goto #18                                                                                                                                     ││││││││    
   17 ─ %46 = %new(Base.DimensionMismatch, &quot;arrays could not be broadcast to a common size&quot;)::DimensionMismatch                                            ││││││││╻           Type
   │          (Base.Broadcast.throw)(%46)                                                                                                                  ││││││││    
   └───       $(Expr(:unreachable))                                                                                                                        ││││││││    
   18 ┄ %49 = φ (#11 =&gt; %27, #16 =&gt; %23)::Base.OneTo{Int64}                                                                                                │││││││     
   │    %50 = (Core.tuple)(%49)::Tuple{Base.OneTo{Int64}}                                                                                                  │││││││     
   └───       goto #19                                                                                                                                     │││││││     
   19 ─       goto #20                                                                                                                                     ││││││      
   20 ─       goto #21                                                                                                                                     │││││       
   21 ─ %54 = %new(Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Tuple{Base.OneTo{Int64}},typeof(+),Tuple{Array{Int64,1},Array{Union{Missing, Float64},1}}}, +, %19, %50)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Tuple{Base.OneTo{Int64}},typeof(+),Tuple{Array{Int64,1},Array{Union{Missing, Float64},1}}}
   └───       goto #22                                                                                                                                     ││││        
   22 ─ %56 = invoke Base.Broadcast.copy(%54::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Tuple{Base.OneTo{Int64}},typeof(+),Tuple{Array{Int64,1},Array{Union{Missing, Float64},1}}})::Array
   └───       goto #23                                                                                                                                     │││         
   23 ─       goto #24                                                                                                                                     ││          
   24 ─       return %56                  "><pre class="notranslate"><code class="notranslate">julia&gt; @code_warntype [1, 2] + [3.0, missing]
Body::Array
44 1 ── %1  = (Base.getfield)(Bs, 1, true)::Array{Union{Missing, Float64},1}                                                                               │╻╷╷         iterate
   └───       goto #7 if not true                                                                                                                          │           
   2 ┄─ %3  = φ (#1 =&gt; %1, #6 =&gt; %12)::Array{Union{Missing, Float64},1}                                                                                    │           
   │    %4  = φ (#1 =&gt; 2, #6 =&gt; %13)::Int64                                                                                                                │           
45 │          invoke Base.promote_shape(_2::Array{Int64,1}, %3::Array{Union{Missing, Float64},1})                                                          │           
   │    %6  = (Base.slt_int)(1, %4)::Bool                                                                                                                  ││╻           &lt;
   └───       goto #4 if not %6                                                                                                                            ││          
   3 ──       goto #5                                                                                                                                      ││          
   4 ── %9  = (Base.getfield)(Bs, %4, true)::Array{Union{Missing, Float64},1}                                                                              ││╻           getindex
   │    %10 = (Base.add_int)(%4, 1)::Int64                                                                                                                 ││╻           +
   └───       goto #5                                                                                                                                      ││          
   5 ┄─ %12 = φ (#4 =&gt; %9)::Array{Union{Missing, Float64},1}                                                                                               │           
   │    %13 = φ (#4 =&gt; %10)::Int64                                                                                                                         │           
   │    %14 = φ (#3 =&gt; true, #4 =&gt; false)::Bool                                                                                                            │           
   │    %15 = (Base.not_int)(%14)::Bool                                                                                                                    │           
   └───       goto #7 if not %15                                                                                                                           │           
   6 ──       goto #2                                                                                                                                      │           
47 7 ── %18 = (getfield)(Bs, 1)::Array{Union{Missing, Float64},1}                                                                                          │           
   │    %19 = (Core.tuple)(A, %18)::Tuple{Array{Int64,1},Array{Union{Missing, Float64},1}}                                                                 ││╻           broadcasted
   │    %20 = (Base.arraysize)(A, 1)::Int64                                                                                                                │││╻╷╷╷╷       instantiate
   │    %21 = (Base.slt_int)(%20, 0)::Bool                                                                                                                 ││││╻╷╷╷        combine_axes
   │    %22 = (Base.ifelse)(%21, 0, %20)::Int64                                                                                                            │││││┃│││││      broadcast_axes
   │    %23 = %new(Base.OneTo{Int64}, %22)::Base.OneTo{Int64}                                                                                              ││││││┃│││        axes
   │    %24 = (Base.arraysize)(%18, 1)::Int64                                                                                                              ││││││╻╷╷         broadcast_axes
   │    %25 = (Base.slt_int)(%24, 0)::Bool                                                                                                                 │││││││╻╷╷╷        axes
   │    %26 = (Base.ifelse)(%25, 0, %24)::Int64                                                                                                            ││││││││┃│││        map
   │    %27 = %new(Base.OneTo{Int64}, %26)::Base.OneTo{Int64}                                                                                              │││││││││┃│          Type
   │    %28 = (%26 === %22)::Bool                                                                                                                          ││││││╻╷╷╷╷       _bcs
   │    %29 = (Base.and_int)(true, %28)::Bool                                                                                                              │││││││╻           _bcs1
   └───       goto #9 if not %29                                                                                                                           ││││││││┃           _bcsm
   8 ──       goto #10                                                                                                                                     │││││││││   
   9 ── %32 = (%22 === 1)::Bool                                                                                                                            │││││││││╻           ==
   └───       goto #10                                                                                                                                     │││││││││   
   10 ┄ %34 = φ (#8 =&gt; %29, #9 =&gt; %32)::Bool                                                                                                               ││││││││    
   └───       goto #12 if not %34                                                                                                                          ││││││││    
   11 ─       goto #18                                                                                                                                     ││││││││    
   12 ─ %37 = (%22 === %26)::Bool                                                                                                                          │││││││││╻╷          ==
   │    %38 = (Base.and_int)(true, %37)::Bool                                                                                                              ││││││││││╻           &amp;
   └───       goto #14 if not %38                                                                                                                          │││││││││   
   13 ─       goto #15                                                                                                                                     │││││││││   
   14 ─ %41 = (%26 === 1)::Bool                                                                                                                            │││││││││╻           ==
   └───       goto #15                                                                                                                                     │││││││││   
   15 ┄ %43 = φ (#13 =&gt; %38, #14 =&gt; %41)::Bool                                                                                                             ││││││││    
   └───       goto #17 if not %43                                                                                                                          ││││││││    
   16 ─       goto #18                                                                                                                                     ││││││││    
   17 ─ %46 = %new(Base.DimensionMismatch, "arrays could not be broadcast to a common size")::DimensionMismatch                                            ││││││││╻           Type
   │          (Base.Broadcast.throw)(%46)                                                                                                                  ││││││││    
   └───       $(Expr(:unreachable))                                                                                                                        ││││││││    
   18 ┄ %49 = φ (#11 =&gt; %27, #16 =&gt; %23)::Base.OneTo{Int64}                                                                                                │││││││     
   │    %50 = (Core.tuple)(%49)::Tuple{Base.OneTo{Int64}}                                                                                                  │││││││     
   └───       goto #19                                                                                                                                     │││││││     
   19 ─       goto #20                                                                                                                                     ││││││      
   20 ─       goto #21                                                                                                                                     │││││       
   21 ─ %54 = %new(Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Tuple{Base.OneTo{Int64}},typeof(+),Tuple{Array{Int64,1},Array{Union{Missing, Float64},1}}}, +, %19, %50)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Tuple{Base.OneTo{Int64}},typeof(+),Tuple{Array{Int64,1},Array{Union{Missing, Float64},1}}}
   └───       goto #22                                                                                                                                     ││││        
   22 ─ %56 = invoke Base.Broadcast.copy(%54::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Tuple{Base.OneTo{Int64}},typeof(+),Tuple{Array{Int64,1},Array{Union{Missing, Float64},1}}})::Array
   └───       goto #23                                                                                                                                     │││         
   23 ─       goto #24                                                                                                                                     ││          
   24 ─       return %56                  
</code></pre></div>
<p dir="auto">As you can see, the resultant output is (correctly but imprecisely) inferred to be <code class="notranslate">Array</code> (not even <code class="notranslate">Vector</code>?).</p>
<p dir="auto">I find this example interesting for two reasons</p>
<ol dir="auto">
<li>Performance (resulting from imprecise inference)</li>
<li>Predictable interface provided by output container</li>
</ol>
<p dir="auto">Regarding performance, I find it quite usual to combine combinations of "functional" operations like <code class="notranslate">+</code>, <code class="notranslate">map</code>, etc, together with hand-written loops in the same scope. In fact, predictably good performance over loops, recursion, higher-order programming, etc is kind of one of our main selling points. In the above, performance will be pessimised if I loop over the output since neither the container type (even the array dimensionality is lost, somehow!) nor the element type is well known. I'm guessing but I'd predict that <code class="notranslate">Vector{Union{Missing, Float64}}</code> would be fastest for subsequent iteration, but it's possible that if inference found something like <code class="notranslate">Vector{&lt;:Union{Missing, Float64}}</code> then this would also be quite fast (I'm not sure, really).</p>
<p dir="auto">Regarding the second, more semantic issue of what the output <em>actually</em> becomes at run time, I'm a bit confused about what I'm meant to assume I can <em>do</em> with the output container. For these input <em>types</em>, we can get</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="julia&gt; Int[] + Union{Float64, Missing}[]
0-element Array{Union{Missing, Float64},1}

julia&gt; Int[1] + Union{Float64, Missing}[3.0]
1-element Array{Float64,1}:
 4.0

julia&gt; Int[2] + Union{Float64, Missing}[missing]
1-element Array{Missing,1}:
 missing

julia&gt; Int[1, 2] + Union{Float64, Missing}[3.0, missing]
2-element Array{Union{Missing, Float64},1}:
 4.0     
  missing"><pre class="notranslate">julia<span class="pl-k">&gt;</span> Int[] <span class="pl-k">+</span> Union{Float64, Missing}[]
<span class="pl-c1">0</span><span class="pl-k">-</span>element Array{Union{Missing, Float64},<span class="pl-c1">1</span>}

julia<span class="pl-k">&gt;</span> Int[<span class="pl-c1">1</span>] <span class="pl-k">+</span> Union{Float64, Missing}[<span class="pl-c1">3.0</span>]
<span class="pl-c1">1</span><span class="pl-k">-</span>element Array{Float64,<span class="pl-c1">1</span>}<span class="pl-k">:</span>
 <span class="pl-c1">4.0</span>

julia<span class="pl-k">&gt;</span> Int[<span class="pl-c1">2</span>] <span class="pl-k">+</span> Union{Float64, Missing}[<span class="pl-c1">missing</span>]
<span class="pl-c1">1</span><span class="pl-k">-</span>element Array{Missing,<span class="pl-c1">1</span>}<span class="pl-k">:</span>
 <span class="pl-c1">missing</span>

julia<span class="pl-k">&gt;</span> Int[<span class="pl-c1">1</span>, <span class="pl-c1">2</span>] <span class="pl-k">+</span> Union{Float64, Missing}[<span class="pl-c1">3.0</span>, <span class="pl-c1">missing</span>]
<span class="pl-c1">2</span><span class="pl-k">-</span>element Array{Union{Missing, Float64},<span class="pl-c1">1</span>}<span class="pl-k">:</span>
 <span class="pl-c1">4.0</span>     
  <span class="pl-c1">missing</span></pre></div>
<p dir="auto">As a programmer, this scares me somewhat because I might get subtly different program behavior (or program correctness) depending on my input data. My concerm is that I might perform tests with mixtures of <code class="notranslate">Missing</code> and <code class="notranslate">Float64</code> input values but be caught out in rare cases in production when all (or none) of the inputs are <code class="notranslate">missing</code>.</p>
<p dir="auto">In this hypothetical scenario, my (tested, production) code might look something like</p>
<div class="highlight highlight-source-julia notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="vec3 = vec1 + vec2
for i in keys(vec3)
    if isless(vec3[i], 0) # vec3 can't have any negative elements
        vec3[i] = missing
    end
end
return vec3"><pre class="notranslate">vec3 <span class="pl-k">=</span> vec1 <span class="pl-k">+</span> vec2
<span class="pl-k">for</span> i <span class="pl-k">in</span> <span class="pl-c1">keys</span>(vec3)
    <span class="pl-k">if</span> <span class="pl-c1">isless</span>(vec3[i], <span class="pl-c1">0</span>) <span class="pl-c"><span class="pl-c">#</span> vec3 can't have any negative elements</span>
        vec3[i] <span class="pl-k">=</span> <span class="pl-c1">missing</span>
    <span class="pl-k">end</span>
<span class="pl-k">end</span>
<span class="pl-k">return</span> vec3</pre></div>
<p dir="auto">But unfortunately this would sometimes fail, depending on my input data, which may vary in size and quality (and maybe 1 in 10,000 times are all non-<code class="notranslate">missing</code>).</p>
<p dir="auto">As a coder, I need to be able to predict the interface provided by the outputs of operation so I can write reliable code. Generally, I've noted that the output of <code class="notranslate">+</code>, <code class="notranslate">map</code>, <code class="notranslate">broadcast</code>, <code class="notranslate">filter</code> (for <code class="notranslate">Array</code> inputs) tend to be mutable <code class="notranslate">Array</code>s, and generally am unafraid to mutate them. Naively, I would track in my head the eltypes of <code class="notranslate">vec1</code> and <code class="notranslate">vec2</code> and assume I can populate <code class="notranslate">vec3</code> with anything consistent.</p>
<p dir="auto">I'm not sure what the best solution is, but from my perspective I find any potential (performance?) gains in returning the narrowest container that fits the run-time data questionable in value compared to understanding the semantic guarantees as a code author.</p>