I (naively) thought that the compiler would do some basic loop unrolling. This is particularly important for generating type-stable code. Is there a way I can easily make the following code snippet stable?
abstract type A end
struct Ax <: A end
struct Ay <: A end
struct Az <: A end
bar(a::Ax) = println("Ax")
bar(a::Ay) = println("Ay")
bar(a::Az) = println("Az")
function foo()
for a in (Ax(), Ay(), Az())
bar(a)
end
end
foo()
The @code_warnings
output is
julia> @code_warntype foo()
MethodInstance for foo()
from foo() in Main at <filetree>
Arguments
#self#::Core.Const(foo)
Locals
@_2::Union{Nothing, Tuple{Union{Ax, Ay, Az}, Int64}}
a::Union{Ax, Ay, Az}
Body::Nothing
1 β %1 = Main.Ax()::Core.Const(Ax())
β %2 = Main.Ay()::Core.Const(Ay())
β %3 = Main.Az()::Core.Const(Az())
β %4 = Core.tuple(%1, %2, %3)::Core.Const((Ax(), Ay(), Az()))
β (@_2 = Base.iterate(%4))
β %6 = (@_2::Core.Const((Ax(), 2)) === nothing)::Core.Const(false)
β %7 = Base.not_int(%6)::Core.Const(true)
βββ goto #4 if not %7
2 β %9 = @_2::Tuple{Union{Ax, Ay, Az}, Int64}
β (a = Core.getfield(%9, 1))
β %11 = Core.getfield(%9, 2)::Int64
β Main.bar(a)
β (@_2 = Base.iterate(%4, %11))
β %14 = (@_2 === nothing)::Bool
β %15 = Base.not_int(%14)::Bool
βββ goto #4 if not %15
3 β goto #2
4 β return nothing
where a::Union{Ax, Ay, Az}
and Tuple{Union{Ax, Ay, Az}, Int64}
are red (not type stable).
Obviously, I could manually unroll the loopβ¦
function foo_manual()
bar(Ax())
bar(Ay())
bar(Az())
end
β¦which is indeed type stable. But this doesnβt scale for larger problems (plus this doesnβt seem very βJulianβ).
Thanks in advance!