>> Well it seems Julia should know that nothing is used from fn!, without
>> knowing anything about fn!. That is at least what @code_warntype
>> suggest (with julia --inline=no). For
>>
>> function f(ar)
>> for i=1:n
>> hh!(ar, i)
>> end
>> end
>>
>> the loop gives:
>>
>> GenSym(1) = $(Expr(:call1, :(top(next)), GenSym(0), :(#s1::Int64)))
>> i = $(Expr(:call1, :(top(getfield)), GenSym(1), 1))
>> #s1 = $(Expr(:call1, :(top(getfield)), GenSym(1), 2)) # line 71:
>> $(Expr(:call1, :hh!, :(ar::Array{Float64,1}), :(i::Int64)))
>> 3:
>> unless $(Expr(:call1, :(top(!)), :($(Expr(:call1, :(top(!)),
>> :($(Expr(:call1, :(top(done)), GenSym(0), :(#s1::Int64))))))))) goto 2
>>
>> For
>> function g(fn!,ar)
>> a = 0
>> for i=1:n
>> fn!(ar, i)
>> end
>> a
>> end
>>
>> the loop gives:
>> 2:
>> GenSym(1) = $(Expr(:call1, :(top(next)), GenSym(0), :(#s1::Int64)))
>> i = $(Expr(:call1, :(top(getfield)), GenSym(1), 1))
>> #s1 = $(Expr(:call1, :(top(getfield)), GenSym(1), 2)) # line 78:
>> (fn!::F)(ar::Array{Float64,1},i::Int64)::Any
>>
>
> Wouldn't it (or fn!) need to allocate for this Any here ^
>
> IIUC its fn! that decides if it returns something, and even if the caller
> doesn't need it, the return value still has to be stored somewhere.
I think this optimisation should work irrespective of what fn! returns
by the fact that the value is not used. This and more seems to happen
in the first-order function. Here a version of first-order
function which calls a function which returns an inferred Any:
const aa = Any[1]
hh_ret!(ar,i) = (ar[i] = hh(ar[i]); aa[1])
function f_ret(ar)
a = aa[1]
for i=1:n
a=hh_ret!(ar, i)
end
a
end
julia> @time f_ret(a);
elapsed time: 0.259893608 seconds (160 bytes allocated)
It's still fast and doesn't allocate, even though it uses the value!
> Maybe fn! does the allocating, but it still happens.
It's a different story if there is actual allocation in fn!.
>> 3:
>> unless $(Expr(:call1, :(top(!)), :($(Expr(:call1, :(top(!)),
>> :($(Expr(:call1, :(top(done)), GenSym(0), :(#s1::Int64))))))))) goto 2
>>
>> So, at least from my naive viewpoint, it looks like there is no need for
>> an allocation in this case. Or is there ever a case when the return
>> value of fn! would be used?
>>
>> I think this is quite different from the case when the return value of
>> fn! is used because then, as long as Julia cannot do type inference on
>> the value of fn!, it cannot know what the type is.
>>
>
> Which is why its ::Any above I guess and my understanding is Any means
> boxed and allocated on the heap?
Thanks for indulging me!