# Understanding Varargs partial specialization

**URL:** <https://discourse.julialang.org/t/understanding-varargs-partial-specialization/102141>\
**Category:** Internals & Design\
**Tags:** compilation, varargs\
**Created:** [July 27, 2023, 5:00am UTC](https://discourse.julialang.org/t/understanding-varargs-partial-specialization/102141 "2023-07-27T05:00:33Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [July 27, 2023, 5:00am UTC](https://discourse.julialang.org/t/understanding-varargs-partial-specialization/102141/1 "2023-07-27T05:00:33Z")

</div>

In the “[Be aware of when Julia avoids specializing](https://docs.julialang.org/en/v1/manual/performance-tips/#Be-aware-of-when-Julia-avoids-specializing)”, section, the following is stated:

> As a heuristic, Julia avoids automatically [specializing](https://docs.julialang.org/en/v1/manual/methods/#man-method-specializations) on argument type parameters in three specific cases: `Type` , `Function` , and `Vararg` . Julia will always specialize when the argument is used within the method, but not if the argument is just passed through to another function.  
> …  
> This will not specialize:

```julia
f_vararg(x::Int...) = tuple(x...)

```

But when I check an untyped version, it looks like it’s specializing by the first element of the `Vararg` and possibly by the rest of the elements if homogenously typed. I say possibly because rerunning this with the nonhomogeneous calls first does not result in the homoegenous-`Vararg` `MethodInstances` (thus only 2 in total). I had expected from the docs that only `f(::Vararg{Any})` would’ve been compiled, so what’s really going on here?

```julia
julia> using MethodAnalysis
julia> f(x...) = tuple(x...)
f (generic function with 1 method)
julia> f(1,1,1)
(1, 1, 1)
julia> f(1.0,1.0,1.0)
(1.0, 1.0, 1.0)
julia> f(1,1.0,1)
(1, 1.0, 1)
julia> f(1.0,1,1.0)
(1.0, 1, 1.0)
julia> methodinstances(f)
4-element Vector{Core.MethodInstance}:
 MethodInstance for f(::Float64, ::Vararg{Any})
 MethodInstance for f(::Int64, ::Vararg{Any})
 MethodInstance for f(::Float64, ::Vararg{Float64})
 MethodInstance for f(::Int64, ::Vararg{Int64})

```

---

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [July 27, 2023, 5:41am UTC](https://discourse.julialang.org/t/understanding-varargs-partial-specialization/102141/2 "2023-07-27T05:41:34Z")

</div>

I wonder if this might be related:

> <https://github.com/JuliaLang/julia/issues/35131#issuecomment-599677125>
>
> Using \[\`nspecializations\` from here\](https://gist.github.com/timholy/cb4e2afe15e…9841a6a2ab4d90325cddc), I find the following behavior strange:
> \`\`\`julia
> julia\> function abstractparameters(T::Type, AT::Type)
> @nospecialize T AT
> @assert T \<: AT
> Tst = supertype(T)
> while Tst \<: AT
> T = Tst
> Tst = supertype(T)
> end
> return T.parameters
> end
> abstractparameters (generic function with 1 method)
> 
> julia\> abstractparameters(typeof(rand(3)), AbstractArray)
> svec(Float64, 1)
> 
> julia\> abstractparameters(typeof(rand(Float32, 3)), AbstractArray)
> svec(Float32, 1)
> 
> julia\> abstractparameters(typeof(rand(Int, 3)), AbstractArray)
> svec(Int64, 1)
> 
> julia\> m = first(methods(abstractparameters))
> abstractparameters(T::Type, AT::Type) in Main at REPL\[3\]:2
> 
> julia\> nspecializations(m) # this is what I expect
> 1
> 
> julia\> @generated function f(a::AbstractArray)
> T, N = abstractparameters(a, AbstractArray) # call it from a @generated method
> :($T(1))
> end
> f (generic function with 1 method)
> 
> julia\> f(rand(3))
> 1.0
> 
> julia\> f(rand(Float32, 3))
> 1.0f0
> 
> julia\> nspecializations(m) # this is what I don't want
> 2
> 
> julia\> m.specializations
> Core.TypeMapEntry(Core.TypeMapEntry(nothing, Tuple{typeof(abstractparameters),Type,Type}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type, ::Type), false, false, false), Tuple{typeof(abstractparameters),Type,Type{AbstractArray}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type, ::Type{AbstractArray}), false, false, false)
> \`\`\`
> 
> This is a MWE of a bigger problem: in LoopVectorization, I've measured at least 33 specializations of \`abstractparameters\` despite the fact that both arguments are marked as not being specialiizable. In that case there are specializations on both parameters. Here's 30 of them:
> \`\`\`julia
> julia\> m.specializations.arg1\[1\].targ
> 30-element Array{Any,1}:
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Float32,Tuple{1,3}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Float32,Tuple{1,3}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)  
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Float64,Tuple{1,3}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Float64,Tuple{1,3}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)  
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Float32,Tuple{1,73}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Float32,Tuple{1,73}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Float32,Tuple{1,75}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Float32,Tuple{1,75}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Float32,Tuple{1}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Float32,Tuple{1}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)      
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Float32,Tuple{69,1}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Float32,Tuple{69,1}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Float32,Tuple{73,1}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Float32,Tuple{73,1}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Float32,Tuple{73}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Float32,Tuple{73}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)    
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Float32,Tuple{75,1}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Float32,Tuple{75,1}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Float64,Tuple{1,73}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Float64,Tuple{1,73}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)
> ⋮                                                                                                                                                                                                                                                                                                                                                                                                                  
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Int32,Tuple{73}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Int32,Tuple{73}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)        
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Int32,Tuple{75,1}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Int32,Tuple{75,1}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)    
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Int64,Tuple{1,73}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Int64,Tuple{1,73}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)    
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Int64,Tuple{1,75}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Int64,Tuple{1,75}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)    
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Int64,Tuple{1}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Int64,Tuple{1}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)          
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Int64,Tuple{69,1}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Int64,Tuple{69,1}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)    
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Int64,Tuple{73,1}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Int64,Tuple{73,1}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)    
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Int64,Tuple{73}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Int64,Tuple{73}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)        
> Core.TypeMapEntry(nothing, Tuple{typeof(LoopVectorization.abstractparameters),Type{StaticStridedPointer{Int64,Tuple{75,1}}},Type{VectorizationBase.AbstractStaticStridedPointer}}, nothing, svec(), 0x0000000000000001, 0xffffffffffffffff, MethodInstance for abstractparameters(::Type{StaticStridedPointer{Int64,Tuple{75,1}}}, ::Type{VectorizationBase.AbstractStaticStridedPointer}), false, true, false)
> \`\`\`
