Hi there!

I am working on some Code that is supposed to be a demonstration of how you can create fast and efficient code with just a few easy, readable lines in Julia. Sadly one of the functions turns out to be not typestable with some really weird behaviour, and I dont know why.

Some Background: `f`

, the function in question, should iterate over a combination of indices of a Matrix and reduce them to a single value. Since I want to apply this later to the RGB-channels of an Image, I use multiple dispatch and define a method for `f(x::Array{T,3})`

that just sums `f`

over all relevant slices.

To not bother you with irrelevant details I stripped away as much details as was possible while still recreating the instability. Here’s the Code:

```
function f(v::AbstractMatrix{T}) where T
sum(1 for r in (1,2))
end
function f(ν::AbstractArray{T,3}) where {T}
return @views sum( f(ν[:, :, i]) for i in 1:size(ν, 3))
end
@code_warntype f(zeros(2, 2, 2))
```

```
MethodInstance for f(::Array{Float64, 3})
from f(ν::AbstractArray{T, 3}) where T in Main at In[79]:1
Static Parameters
T = Float64
Arguments
#self#::Core.Const(f)
ν::Array{Float64, 3}
Locals
#59::var"#59#60"{Array{Float64, 3}}
Body::Any
1 ─ %1 = Main.:(var"#59#60")::Core.Const(var"#59#60")
│ %2 = Core.typeof(ν)::Core.Const(Array{Float64, 3})
│ %3 = Core.apply_type(%1, %2)::Core.Const(var"#59#60"{Array{Float64, 3}})
│ (#59 = %new(%3, ν))
│ %5 = #59::var"#59#60"{Array{Float64, 3}}
│ %6 = Main.size(ν, 3)::Int64
│ %7 = (1:%6)::Core.PartialStruct(UnitRange{Int64}, Any[Core.Const(1), Int64])
│ %8 = Base.Generator(%5, %7)::Core.PartialStruct(Base.Generator{UnitRange{Int64}, var"#59#60"{Array{Float64, 3}}}, Any[var"#59#60"{Array{Float64, 3}}, Core.PartialStruct(UnitRange{Int64}, Any[Core.Const(1), Int64])])
│ %9 = Main.sum(%8)::Any
└── return %9
```

Note the returntype of `Any`

. Here are some parts that I find odd about this:

- Even though
`f`

, given an appropriate matrix`view`

is typestable,`f(::Array{T,3})`

is not. - Furthermore, if I check this fact with
`@code_warntype f(zeros(2,2))`

, the instability just ‘goes away’;

if I run

then suddenly everything is typestable. This is confirmed by some Performance testing: when I call`function f(v::AbstractMatrix{T}) where T sum(1 for r in (1,2)) end function f(ν::AbstractArray{T,3}) where {T} return @views sum( f(ν[:, :, i]) for i in 1:size(ν, 3)) end @code_warntype f(zeros(2, 2)) @code_warntype f(zeros(2, 2, 2))`

I get 5 allocations per call, but when I run`function testf() a=zeros(2,2,2) @time f(a) end testf()`

`@code_warntype f(zeros(2, 2))`

beforehand the allocations disappear. - If I replace
`f`

in the generator with any other scalar valued function, e.g.`maximum`

, the instability goes away. - If I just let the first method
`return 2`

, the instability goes away, even though this is of course equivalent (which the compiler knows, as of`@code_llvm f(zeros(2,2)`

).

When trying to recreate the problem I recommend to regularly restart the kernel and only run the proper sections, due to the instable instability ( ) .

I work in a Jupyter Notebook on Windows with a 1.7.2 kernel.

Any help of whats going on here is welcome.