I don't think there's any fundamental reason things can't work as you're
hoping, I just think they all count as optimizations that have not yet been
implemented.
--Tim
On Friday, April 24, 2015 11:19:14 AM Mauro wrote:
> >> 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!