>> 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!

Reply via email to