Inner function overhead

The problem is that the last line in your function m:

Umin = min(Ufirst, Ulast)

Clashes with the outer variable in compute_distance (same variable name Umin):

Umin = min(Uv, Uh)

If you rename any of these variables, or simple replace the first expression with:

return min(Ufirst, Ulast)

The allocation will go away, and the two implementations should perform equally.


Btw, you can use @code_warntype to detect this type of problem:

julia> @code_warntype compute_distance2((grid), CartesianIndex(50, 20), Ifirst, Ilast, 0.1, 3.0)
Body::Any
1 ── %1   = %new(Core.Box)::Core.Box
...

The return type being Any (colored red) and the presence of Core.Box indicates that there’s a problem. You can use a more detailed version of @code_warntype to get a better idea of where the problem occurs (look for the first red Any):

julia> @code_warntype debuginfo=:source compute_distance2((grid), CartesianIndex(50, 20), Ifirst, Ilast, 0.1, 3.0)
...
│    @ inner_function_overhead.jl:49 within 'compute_distance'
│    %163 = (Core.isdefined)(%1, :contents)::Bool
└───        goto #26 if not %163
25 ─        goto #27
26 ─        $(Expr(:throw_undef_if_not, :Umin, false))
27 ┄ %167 = (Core.getfield)(%1, :contents)::Any
│    %168 = (h + %167)::Any

It’s perhaps not super clear, but line 49 corresponds to return min(h+Umin, maxdist), and we can see that Core.isdefined is called for the field Umin which indicates that the compiler is unable to fully deduce what that field is. You might find the output of @code_lowered easier to read.


As for why this happens, it has to do with how scoping works in Julia. If the variable is declared anywhere in the outer scope, and also in an inner scope, it will be available anywhere after the declaration in the inner scope. Not sure if that explanation made sense, but consider these examples:

function test()
    for i = 1:10
        k = i
    end
    println(k)
end

julia> test();
ERROR: UndefVarError: k not defined

And now:

function test()
    for i = 1:10
        k = i
    end
    println(k)
    k = 2
end

julia> test();
10
3 Likes