I’ve often desired to have “optional” execution paths in my code that I could activate from outside of the function. This would be helpful in situations where I have a complex function that does several data processing steps, resulting in some scalar result. However, sometimes there is something wrong with combination of input parameters and input data and I’d like to get access to some results of several processing sub-steps, so that I could plot them, or directly get their plots. On the other hand, having this “visual debugging” data is too expensive for real heavy calculation (think of having tens of 100MB intermediate arrays instead of doing operations inplace).
An idea:
using Plots
global p = plot()
macro debug_step(ex)
return quote
local val = $(esc(ex))
val
end
end
macro with_debug_step(ex)
return quote
local val = $(esc(ex))
val
end
end
macro sayhello(name)
return :( println("Hello, ", $name) )
end
function heavy_calculation(arr, par)
@debug_step plot!(p, deepcopy(arr), label="Orig arr")
arr .-= par #heavy calculation depending on "tuning" parameter
@debug_step plot!(p,deepcopy(arr), label="arr step1")
arr .+= randn(length(arr)) #another heavy calculation
@debug_step plot!(p,deepcopy(arr), label="arr step2")
s = sum(arr)
if s >100
@error("bad par value")
end
s
end
a = [randn(10).+44 for i=1:50]
#test run that with parameter 42 the heavy_calculation is well performing
@with_debug_step heavy_calculation(a[1], 42)
# check that all plots show correct behavior
plot(p)
#and now run again but the heavy_calculation function does not execute the expressions guarded by @debug_step
for aa in a
b = heavy_calculation(a[1], 42)
println(b)
end
here I’ve used stub macro implementation that does nothing. The desired behavior would let @with_debug_step
introduce some variable in the macro domain and it that is set the @debug_step
macro would either execute or do no-op.
What is the right approach to write such cooperating macro pair? Could you give me an example of similar behavior elsewhere?