This thread seems to be relevant
In it, you’ll find the following technique, which also forms the core of the implementation of ToggleableAsserts
. Re-writing your example, it would look like this:
julia> mode_on() = true
mode_on (generic function with 1 method)
julia> function inc!(a)
if mode_on()
a .+= 1
else
a .+= 2
end
end
inc! (generic function with 1 method)
You’ll notice that lowered code is not entirely free of branches:
julia> @code_lowered inc!([1,2,3])
CodeInfo(
1 ─ %1 = Main.mode_on()
└── goto #3 if not %1
2 ─ %3 = Base.broadcasted(Main.:+, a, 1)
│ %4 = Base.materialize!(a, %3)
└── return %4
3 ─ %6 = Base.broadcasted(Main.:+, a, 2)
│ %7 = Base.materialize!(a, %6)
└── return %7
)
But later stages of compilation (starting with typed code) do eliminate branches (note how the second block below is considered unreachable):
julia> @code_warntype inc!([1,2,3])
MethodInstance for inc!(::Vector{Int64})
from inc!(a) in Main at REPL[3]:1
Arguments
#self#::Core.Const(inc!)
a::Vector{Int64}
Body::Vector{Int64}
1 ─ %1 = Main.mode_on()::Core.Const(true)
│ Core.typeassert(%1, Core.Bool)
│ %3 = Base.broadcasted(Main.:+, a, 1)::Core.PartialStruct(Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(+), Tuple{Vector{Int64}, Int64}}, Any[Core.Const(+), Core.PartialStruct(Tuple{Vector{Int64}, Int64}, Any[Vector{Int64}, Core.Const(1)]), Core.Const(nothing)])
│ %4 = Base.materialize!(a, %3)::Vector{Int64}
└── return %4
2 ─ Core.Const(:(Base.broadcasted(Main.:+, a, 2)))
│ Core.Const(:(Base.materialize!(a, %6)))
└── Core.Const(:(return %7))
So I’d say this qualifies as conditional compilation. Furthermore, if the mode_on()
method is redefined, then it will invalidate inc!
and force its re-compilation next time it is called (note how the else
clause is now the only reachable part of the code):
julia> mode_on() = false
mode_on (generic function with 1 method)
julia> @code_warntype inc!([1,2,3])
MethodInstance for inc!(::Vector{Int64})
from inc!(a) in Main at REPL[3]:1
Arguments
#self#::Core.Const(inc!)
a::Vector{Int64}
Body::Vector{Int64}
1 ─ %1 = Main.mode_on()::Core.Const(false)
└── goto #3 if not %1
2 ─ Core.Const(:(Base.broadcasted(Main.:+, a, 1)))
│ Core.Const(:(Base.materialize!(a, %3)))
└── Core.Const(:(return %4))
3 ┄ %6 = Base.broadcasted(Main.:+, a, 2)::Core.PartialStruct(Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(+), Tuple{Vector{Int64}, Int64}}, Any[Core.Const(+), Core.PartialStruct(Tuple{Vector{Int64}, Int64}, Any[Vector{Int64}, Core.Const(2)]), Core.Const(nothing)])
│ %7 = Base.materialize!(a, %6)::Vector{Int64}
└── return %7