Compile time conditions or dispatch removing code based on (DEBUG, LIVE) mode

Note that you can also use the “use functions as global variables” trick.

mode() = :debug

function myfunc()
    if mode() == :debug
        # do this only in debug mode
        println("debugging...")
    end
    println("regular computation")
end

This gives

julia> myfunc()
debugging...
regular computation

julia> @code_typed myfunc()
CodeInfo(
1 ─      goto #3 if not true
2 ─      invoke Main.println("debugging..."::String)::Any
3 ┄ %3 = invoke Main.println("regular computation"::String)::Nothing
└──      return %3
) => Nothing

Redefining, say, mode() = :live will automatically trigger recompilation of myfunc() and, via constant propagation, eliminate the debug branch entirely:

julia> mode() = :live
mode (generic function with 1 method)

julia> myfunc()
regular computation

julia> @code_typed myfunc()
CodeInfo(
1 ─      nothing::Nothing
│   %2 = invoke Main.println("regular computation"::String)::Nothing
└──      return %2
) => Nothing

One advantage of this approach compared to attempting to achieve the same with global variables is that you can’t assign variables in other modules but you can redefine functions in other modules. See GitHub - JuliaPerf/STREAMBenchmark.jl: A version of the STREAM benchmark which measures the sustainable memory bandwidth., where I tell the user to redefine STREAMBenchmark.avxt() = true to make my package STREAMBenchmark use LoopVectorization for multithreading, as an example.

1 Like