I want to do conditional compilation. Besides, when developing, I’d like to be able to exam all branches. Can I do that?
An explanation by case:
My code will have two different modes when used in production, let’s call them on and off. I may write a macro to do that:
const IS_ON = true
macro if_on(ex1, ex2)
if IS_ON
return :($(esc(ex1)))
else
return :($(esc(ex2)))
end
end
function inc_depend_on_mode!(a)
@if_on begin
a .+= 1
end begin
a .+= 2
end
end
I can then change the value of IS_ON to get code for different modes.
This works fine for production. However, when developing, I want to be able to examine code for both modes without restarting my REPL.
Then first, I need to change IS_ON from a global constant, to something like
mutable struct Control
is_on::Bool
end
const control = Control(true)
so that I may dynamically set its value.
There remains one question: how can I recompile function inc_depend_on_mode!
after I change the mode?
Very Important: I want to do real conditional precompilation, which means, in my point of view, that the generated lowered code should be free of branches. In the previous example, this can be confirmed:
julia> a = zeros(Int, 5);
julia> @code_lowered inc_depend_on_mode!(a)
CodeInfo(
1 ─ %1 = Base.broadcasted(Main.:+, a, 1)
│ %2 = Base.materialize!(a, %1)
└── return %2
)
If not, I can simply write something like
mutable struct Control
is_on::Bool
end
const control = Control(true)
function inc_depend_on_mode!(a)
if control.is_on
a .+= 1
else
a .+= 2
end
end
It works fine, but it is not conditional “compilation”, because branches exist in lowered code:
julia> a = zeros(Int, 5);
julia> @code_lowered inc_depend_on_mode!(a)
CodeInfo(
1 ─ %1 = Base.getproperty(Main.control, :is_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
)