An enum to describe the behavior of macros when interacting with @stable.

  • CompatibleMacro: Propagate macro through to both function and simulator.
  • DontPropagateMacro: Do not propagate macro; leave it at the outer block.
  • IncompatibleMacro: Skip the contents of this macro completely.

Globally ignore certain functions when stabilizing. By default, a few functions in Base are ignored, as they are meant to be unstable, and will (hopefully) always be inlined by the compiler.

register_macro!(macro_name::Symbol, behavior::MacroInteractions)

Register a macro with a specified behavior in the MACRO_BEHAVIOR list.

This function adds a new macro and its associated behavior to the global list that tracks how macros should be treated when encountered during the stabilization process. The behavior can be one of CompatibleMacro, IncompatibleMacro, or DontPropagateMacro, which influences how the @stable macro interacts with the registered macro.

The default behavior for @stable is to assume CompatibleMacro unless explicitly declared.


  • macro_name::Symbol: The symbol representing the macro to register.
  • behavior::MacroInteractions: The behavior to associate with the macro, which dictates how it should be handled.


using DispatchDoctor: register_macro!, IncompatibleMacro

register_macro!(Symbol("@mymacro"), IncompatibleMacro)
allow_unstable(f::F) where {F<:Function}

Globally disable type DispatchDoctor instability checks within the provided function f.

This function allows you to execute a block of code where type instability checks are disabled. It ensures that the checks are re-enabled after the block is executed, even if an error occurs.

This function uses a ReentrantLock and will throw an error if used from two tasks at once.


allow_unstable() do
    # do unstable stuff


  • f::F: A function to be executed with type instability checks disabled.


  • The result of the function f.


You cannot call allow_unstable from two tasks at once. An error will be thrown if you try to do so.

@stable [options...] [code_block]

A macro to enforce type stability in functions. When applied, it ensures that the return type of the function is concrete. If type instability is detected, a TypeInstabilityError is thrown.


  • default_mode::String="error":
    • Change the default mode from "error" to "warn" to only emit a warning, or "disable" to disable type instability checks by default.
    • To locally or globally override the mode for a package that uses DispatchDoctor, you can use the "instability_check" key in your LocalPreferences.toml (typically configured with Preferences.jl).
  • default_codegen_level::String="debug":
    • Set the code generation level to "min" to only generate a single function body for each stabilized function. The default, "debug", generates an entire duplicate function so that @code_warntype can be used.
    • To locally or globally override the code generation level for a package that uses DispatchDoctor, you can use the "instability_check_codegen_level" key in your LocalPreferences.toml.
  • default_union_limit::Int=1:
    • Sets the maximum elements in a union to be considered stable. The default is 1, meaning that all unions are considered unstable. A value of 2 would indicate that Union{Float32,Float64} is considered stable, but Union{Float16,Float32,Float64} is not.
    • To locally or globally override the union limit for a package that uses DispatchDoctor, you can use the "instability_check_union_limit" key in your LocalPreferences.toml.


using DispatchDoctor: @stable

@stable function relu(x)
    if x > 0
        return x
        return 0.0

which will automatically flag any type instability:

julia> relu(1.0)

julia> relu(0)
ERROR: TypeInstabilityError: Instability detected in function `relu`
with arguments `(Int64,)`. Inferred to be `Union{Float64, Int64}`,
which is not a concrete type.

Extended help

You may also apply @stable to arbitrary blocks of code, such as begin or module, and have it be applied to all functions. (Just note that this skips closure functions.)

using DispatchDoctor: @stable

@stable begin
    f(x) = x
    g(x) = x > 0 ? x : 0.0
    @unstable begin
        g(x::Int) = x > 0 ? x : 0.0
    module A
        h(x) = x

This @stable will apply to f, g, h, as well as all functions within myfile.jl. It skips the definition g(x::Int), meaning that when Int input is provided to g, type instability is not detected.