Type instablility

I am playing with the CartesianIndex and here is a simple function to set the elements to 0 outside a centered N-sphere in a N-dimensional array.

julia> function test!(A::AbstractArray{T}, r::Int) where {T <: Real}
         ctr = [(size(A, d)+1)/2 for d in 1:ndims(A)]
         R = CartesianRange(size(A))
         for I in R
           (sum(abs2, (I.I .- ctr)) > r^2) && (A[I] = zero(T))
         end
         nothing
       end
test! (generic function with 1 method)

julia> A = rand(5, 5)
5×5 Array{Float64,2}:
 0.493302  0.536014  0.392092   0.913987  0.379203
 0.059023  0.927097  0.859462   0.875942  0.832613
 0.217616  0.137665  0.0311417  0.591856  0.598981
 0.28981   0.670475  0.454813   0.60883   0.558579
 0.523627  0.109789  0.343885   0.782731  0.386419

julia> @code_warntype test!(A, 2)
Variables:
  #self#::#test!
  A::Array{Float64,2}
  r::Int64
  I@_4::CartesianIndex{2}
  #temp#@_5::CartesianIndex{2}
  #5@_6::##5#6{Array{Float64,2}}
  ctr::Array{Float64,1}
  R::CartesianRange{CartesianIndex{2}}
  #3::Base.IteratorsMD.##3#4
  #5@_10::Base.IteratorsMD.##5#6{Int64}
  #temp#@_11::CartesianIndex{2}
  newtail::Tuple{Int64}
  #temp#@_13::Tuple{Int64,Int64}
  T::Any
  shape::Tuple{Base.OneTo{Int64}}
  iter::CartesianRange{CartesianIndex{1}}
  newout::Base.OneTo{Int64}
  C::Array{Float64,1}
  keeps@_19::Tuple{Tuple{Bool},Tuple{Bool}}
  Idefaults@_20::Tuple{Tuple{Int64},Tuple{Int64}}
  #temp#@_21::Int64
  keeps@_22::Tuple{Tuple{Bool}}
  Idefaults@_23::Tuple{Tuple{Int64}}
  #temp#@_24::Int64
  keep@_25::Tuple{Bool}
  Idefault@_26::Tuple{Int64}
  #temp#@_27::Int64
  A1::Any
  keeps@_29::Tuple{}
  Idefaults@_30::Tuple{}
  #temp#@_31::Int64
  keep@_32::Tuple{Bool}
  Idefault@_33::Tuple{Int64}
  #temp#@_34::Int64
  ind1@_35::Base.OneTo{Int64}
  keep@_36::Tuple{}
  Idefault@_37::Tuple{}
  #temp#@_38::Int64
  ind1@_39::Base.OneTo{Int64}
  keep@_40::Tuple{}
  Idefault@_41::Tuple{}
  #temp#@_42::Int64
  I_1::CartesianIndex{1}
  I_2::CartesianIndex{1}
  val_1::Int64
  val_2::Float64
  result::Float64
  I@_48::CartesianIndex{1}
  i#660::Int64
  I@_50::CartesianIndex{1}
  n#659::Int64
  i#658::CartesianIndex{0}
  #temp#@_53::Bool
  r#657::CartesianRange{CartesianIndex{1}}
  A_1::Tuple{Int64,Int64}
  A_2::Any
  keep_1::Tuple{Bool}
  keep_2::Tuple{Bool}
  Idefault_1::Tuple{Int64}
  Idefault_2::Tuple{Int64}
  #temp#@_61::Any
  fx::Float64
  ......

How do I make this function type stable? Thanks!

performance of captured variables in closures · Issue #15276 · JuliaLang/julia · GitHub?

You can try a function barrier (introduce a local function taking ctr and A as input)

Thanks for the reply! I am aware of using function barrier here. I want to know how to eliminate the type instability issue in this function altogether. Maybe not as easy as I expected.

I actually think it’s already type stable. The Anys are only for variables that are optimized out.

See https://github.com/JuliaLang/julia/pull/23280. On the latest nightly version of Julia, all of the Anys are replaced with <optimized out>.

Thanks for pointing this out! I think you are right. This function is already type stable.