I found the following behavior a bit strange. When defining a function anonymously, broadcasting it introduces type instability?
julia> f = x -> x^2 # Simple function
#1 (generic function with 1 method)
julia> @code_warntype f(5) # non-broadcasting works fine
MethodInstance for (::var"#1#2")(::Int64)
from (::var"#1#2")(x) @ Main REPL[1]:1
Arguments
#self#::Core.Const(var"#1#2"())
x::Int64
Body::Int64
1 β %1 = Main.:^::Core.Const(^)
β %2 = Core.apply_type(Base.Val, 2)::Core.Const(Val{2})
β %3 = (%2)()::Core.Const(Val{2}())
β %4 = Base.literal_pow(%1, x, %3)::Int64
βββ return %4
julia> @code_warntype f.(5) # Broadcasting it results in ::Any
MethodInstance for (::var"##dotfunction#230#3")(::Int64)
from (::var"##dotfunction#230#3")(x1) @ Main none:0
Arguments
#self#::Core.Const(var"##dotfunction#230#3"())
x1::Int64
Body::Any
1 β %1 = Base.broadcasted(Main.f, x1)::Union{Base.Broadcast.Broadcasted{<:Base.Broadcast.BroadcastStyle, Nothing, Int64, Tuple{}}, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{0}, Nothing, _A, Tuple{Int64}} where _A}
β %2 = Base.materialize(%1)::Any
βββ return %2
However, when defining the function βnormallyβ it works fine.
julia> function f2(x)
x^2
end
f2 (generic function with 1 method)
julia> @code_warntype f2.(5)
MethodInstance for (::var"##dotfunction#231#4")(::Int64)
from (::var"##dotfunction#231#4")(x1) @ Main none:0
Arguments
#self#::Core.Const(var"##dotfunction#231#4"())
x1::Int64
Body::Int64
1 β %1 = Base.broadcasted(Main.f2, x1)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{0}, Nothing, typeof(f2), Tuple{Int64}}
β %2 = Base.materialize(%1)::Int64
βββ return %2
AFAIK Iβm not doing anything weird surrounding f
that should cause type instability?
I first noticed this when investigating some allocations related to a struct holding a simple function like f
. When I replaced broadcasting with for-loops allocations were reduced to expected levels and @code_warntype
was happy. Have I missed something about anonymous functions or is this known?