Reference
Macros
DispatchDoctor._Macros.@stable
— Macro@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.
Options
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).
- Change the default mode from
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.
- Set the code generation level to
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 of2
would indicate thatUnion{Float32,Float64}
is considered stable, butUnion{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.
- Sets the maximum elements in a union to be considered stable. The default is
Example
using DispatchDoctor: @stable
@stable function relu(x)
if x > 0
return x
else
return 0.0
end
end
which will automatically flag any type instability:
julia> relu(1.0)
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
end
module A
h(x) = x
include("myfile.jl")
end
end
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.
DispatchDoctor._Macros.@unstable
— Macro@unstable [code_block]
A no-op macro to hide blocks of code from @stable
.
Utilities
If you wish to turn off @stable
for a single function call, you can use allow_unstable
:
DispatchDoctor._RuntimeChecks.allow_unstable
— Functionallow_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.
Usage
allow_unstable() do
# do unstable stuff
end
Arguments
f::F
: A function to be executed with type instability checks disabled.
Returns
- The result of the function
f
.
Notes
You cannot call allow_unstable
from two tasks at once. An error will be thrown if you try to do so.
@stable
will normally interact with macros by propagating them to the function definition as well as the function simulator. If you would like to change this behavior, or declare a macro as being incompatible with @stable
, you can use register_macro!
:
DispatchDoctor._Interactions.register_macro!
— Functionregister_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.
Arguments
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.
Examples
using DispatchDoctor: register_macro!, IncompatibleMacro
register_macro!(Symbol("@mymacro"), IncompatibleMacro)
Internals
DispatchDoctor._Utils.type_instability
— Functiontype_instability(T::Type)
Returns true if this type is not concrete. Will also return false for Union{}
, so that errors can propagate.