# \[ANN\] DispatchDoctor.jl 🩺 – offers you a prescription for type stability

**URL:** <https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837>\
**Category:** Package Announcements\
**Created:** [May 28, 2024, 1:07pm UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837 "2024-05-28T13:07:16Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [May 28, 2024, 1:07pm UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/1 "2024-05-28T13:07:16Z")

</div>

Announcing…

# [DispatchDoctor](https://github.com/MilesCranmer/DispatchDoctor.jl/tree/main) 🩺

_The doctor’s orders: no type instability allowed!_

[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://astroautomata.com/DispatchDoctor.jl/dev/) [![Build Status](https://github.com/MilesCranmer/DispatchDoctor.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/MilesCranmer/DispatchDoctor.jl/actions/workflows/CI.yml?query=branch%3Amain) [![Coverage](https://coveralls.io/repos/github/MilesCranmer/DispatchDoctor.jl/badge.svg?branch=main)](https://coveralls.io/github/MilesCranmer/DispatchDoctor.jl?branch=main) [![Aqua QA](https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg)](https://github.com/JuliaTesting/Aqua.jl) [![](https://img.shields.io/badge/%F0%9F%9B%A9%EF%B8%8F_tested_with-JET.jl-ffffff)](https://github.com/aviatesk/JET.jl)

This experimental package provides the `@stable` macro to enforce that functions have type stable return values.

```julia
using DispatchDoctor: @stable

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

```

Calling this function will throw an error for any type instability:

```julia
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.

```

Code which is type stable should compile away the check:

```julia
julia> @stable f(x) = x;

```

with `@code_llvm f(1)`:

```llvm
define i64 @julia_f_12055(i64 signext %"x::Int64") #0 {
top:
  ret i64 %"x::Int64"
}

```

Meaning there is zero overhead on this particular type stability check. (Please post an issue for any known examples of this not being the case!)

You can also use `@stable` on entire blocks of code, including `begin-end` blocks, `module`, and anonymous functions – it will propagate through everything and “stabilize” all functions. The inverse of `@stable` is `@unstable` which toggles it back off.

```julia
@stable begin
    f() = rand(Bool) ? 0 : 1.0

    module A
        # Will apply to code inside modules:
        g(; a, b) = a + b

        # Will recursively apply to included files:
        include("myfile.jl")
        module B # as well as nested submodules!

            # `@unstable` inverts `@stable`:
            using DispatchDoctor: @unstable
            @unstable h() = rand(Bool) ? 0 : 1.0

            # This can also apply to code blocks:
            @unstable begin
                h(x::Int) = rand(Bool) ? 0 : 1.0
                # ^ And target specific methods
            end
        end
    end
end

```

All methods in the block will be wrapped with the type stability check:

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

```

(_Tip: in the REPL, you must wrap modules with `@eval`, because the REPL has special handling of the `module` keyword._)

You can disable stability errors for a single scope with the `allow_unstable` context:

```julia
julia> @stable f(x) = x > 0 ? x : 0.0

julia> allow_unstable() do
           f(1)
       end
1

```

although this will error if you try to use it simultaneously from two separate threads.

Note that instability errors are also automatically skipped during precompilation.

**Note!**

`@stable` will have no effect on code if it is:

- Within an `@unstable` block
- Within a macro definition
- A function inside another function (i.e., a closure) – although the wrapping function will still get checked (see [this example](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/4))
- A generated function
- Within an `@eval` statement
- Within a `quote` block
- If the function name is an expression (such as parameterized functions like `MyType{T}(args...) = ...`)

You can safely use `@stable` to wrap any of these cases; they will simply be ignored. Although, if you use `@stable` _internally_ in any of these cases, (like calling `@stable` directly on a closure), then it will apply.

And of course if you find other cases of `@stable` not playing well with certain Julia features, please raise an issue.

Also, `@stable` is a no-op in unsupported Julia versions (before 1.10) (and also any future Julia versions I haven’t tested yet)

## Credits

Many thanks to @Elrod, @thofma, @matthias314 and others for tips on [Improving speed of runtime dispatch detector](https://discourse.julialang.org/t/improving-speed-of-runtime-dispatch-detector/114697)

---

<div class="post-metadata">

**Author:** ![roflmaostc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roflmaostc/32/30123_2.png) [@roflmaostc](https://discourse.julialang.org/u/roflmaostc)\
**Post date:** [May 28, 2024, 2:50pm UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/2 "2024-05-28T14:50:02Z")

</div>

> [@MilesCranmer](#):
>
> A function inside another function (i.e., a closure)

For me this is the most common source of type instabilities since my functional style of programming includes a lot of closures.

Is it planned in future? As long [15276](https://github.com/JuliaLang/julia/issues/15276) is open, this would be a killer feature for me.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [May 28, 2024, 3:13pm UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/3 "2024-05-28T15:13:21Z")

</div>

> [@roflmaostc](#):
>
> For me this is the most common source of type instabilities since my functional style of programming includes a lot of closures.

It should already work for many cases. What I meant was that in the case of

```julia
@stable function f(x)
    function inner()
        x
    end
    inner()
end

```

You would stabilize `f`, but not `inner`. So if `f` has a type instability resulting from `inner`, that would still be caught!

If you meant: can you also have it check the output of `inner`, then yes, you can do

```julia
@stable function f(x)
    @stable function inner()
        x
    end
    inner()
end

```

And it will check both that the output of `inner` is type stable, as well as the output of `f`.

It basically just doesn’t propagate `@stable` into closures, if that makes sense. But I could certainly reconsider this. I just didn’t want it to start getting applied to all the little closures in things like `map(x -> x^2, ar)` which would IMO be overkill. But maybe people want that?

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [May 28, 2024, 3:17pm UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/4 "2024-05-28T15:17:41Z")

</div>

For example:

```julia
julia> @stable function f(x)
           function inner()
               x = x
               x
           end
           inner()
       end
f (generic function with 1 method)

julia> f(1)
ERROR: TypeInstabilityError: Instability detected in `f`
defined at REPL[4]:1 with arguments `(Int64,)`. Inferred
to be `Any`, which is not a concrete type.

```

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [May 28, 2024, 3:25pm UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/5 "2024-05-28T15:25:20Z")

</div>

> [@MilesCranmer](#):
>
> I just didn’t want it to start getting applied to all the little closures in things like `map(x -> x^2, ar)` which would IMO be overkill.

Hm, I think this isn’t a particularly strong counter-argument, because, at least in my experience, those “one liner” closures are 99.9999% of the times type-stable, so the macro anyways wouldn’t block anything, right?

Or are you worried for drastic increases in compile time?

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [May 28, 2024, 3:34pm UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/6 "2024-05-28T15:34:36Z")

</div>

I guess I just assumed that if your top-level functions were type stable, then your closures are also very likely type stable. So individual functions are a good “atomic unit” for debugging things.

And if only the closures themselves are unstable, but not the function, then the closures probably do something that isn’t important, like log debugging information or something (which wouldn’t need to be type stable anyways).

But if people want I could change that. I just thought it didn’t make much sense (but I welcome arguments otherwise, I just can’t think of any!).

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [May 28, 2024, 3:51pm UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/7 "2024-05-28T15:51:02Z")

</div>

> [@MilesCranmer](#):
>
> ```julia
> @stable enable=parse(Bool, get(ENV, "MY_VAR", "false")) begin
> 
> ```

Could you implement a switch based on Preferences.jl? This way I could setup a CI test environment that has this enabled. Otherwise, it might be a good idea to disable this by default when deployed to the user.

---

<div class="post-metadata">

**Author:** ![wsmoses](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsmoses/32/26497_2.png) [@wsmoses](https://discourse.julialang.org/u/wsmoses)\
**Post date:** [May 28, 2024, 3:51pm UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/8 "2024-05-28T15:51:23Z")

</div>

This is incredibly useful.

It would indeed be nice to find closures. They often result in type instabilities that present a bunch of issues (see here for a longer description: [https://github.com/tpapp/LogDensityProblemsAD.jl/pull/29#discussion\_r1597685998](https://github.com/tpapp/LogDensityProblemsAD.jl/pull/29#discussion_r1597685998)).

Fun fact the fact that Threads.@threads creates a closure with this issue is why Enzyme actually vendors its own closure-free parallel for construct: [Enzyme.jl/test/threads.jl at 1e45f264dbd2dacd79686c891f2d8c42ead33fce · EnzymeAD/Enzyme.jl · GitHub](https://github.com/EnzymeAD/Enzyme.jl/blob/1e45f264dbd2dacd79686c891f2d8c42ead33fce/test/threads.jl#L101)

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [May 28, 2024, 4:11pm UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/9 "2024-05-28T16:11:49Z")

</div>

> [@mkitti](#):
>
> Could you implement a switch based on [Preferences.jl](https://juliahub.com/ui/Packages/General/Preferences)? This way I could setup a CI test environment that has this enabled. Otherwise, it might be a good idea to disable this by default when deployed to the user.

Sure! Could you say a bit more about what you envision as the ideal setup?

Do you mean that all `@stable` in all packages could be enabled/disabled with a single Preferences.jl setting (sort of like it’s a compiler option), overriding any choice of `enable`?

Or would the `enable` option default to something set by Preferences.jl (again, like a compiler option), but a package could individually override it if they set it explicitly?

I haven’t used Preferences.jl before so not super clear on how it works.

> [@wsmoses](#):
>
> This is incredibly useful.

Thanks!

> [@wsmoses](#):
>
> It would indeed be nice to find closures. They often result in type instabilities that present a bunch of issues (see here for a longer description: [https://github.com/tpapp/LogDensityProblemsAD.jl/pull/29#discussion\_r1597685998](https://github.com/tpapp/LogDensityProblemsAD.jl/pull/29#discussion_r1597685998)).

Just to check, would the type instability still show up in the return value of the wrapping function? Or is it rather an internal type instability?

---

<div class="post-metadata">

**Author:** ![wsmoses](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsmoses/32/26497_2.png) [@wsmoses](https://discourse.julialang.org/u/wsmoses)\
**Post date:** [May 28, 2024, 4:14pm UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/10 "2024-05-28T16:14:44Z")

</div>

I think it could propagate through the return, but also may also just show up internally (depending on the closure definition).

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [May 28, 2024, 4:21pm UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/11 "2024-05-28T16:21:10Z")

</div>

Thanks. So if the instability propagates through the wrapping function’s return value then it should still get flagged (like [this one](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/4)). I guess the question then is if you would want to also have closures get flagged automatically if they _don’t propagate_ to the return value.

The current behavior is to not do this (for the reasons [here](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/6)) but I could always change it, or maybe add another macro option to always recurse through functions.

I should also note that it still won’t be able to flag the closures generated by `Threads.@threads` unless those instabilities affect the function’s return value (since `@stable` would presumably do its processing before `@threads`). But maybe we could add special behavior for certain macros to support a lazy expansion.

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [May 28, 2024, 5:55pm UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/12 "2024-05-28T17:55:16Z")

</div>

If people start using this then great! Except, if in packages, then it can be type stable for e.g. types you care about (I guess all the main types), but then not for some exotic one, say for types like in Dec64.jl or for posits, when composing with packages that use `@stable`.

I didn’t check, but it would be nice to have an escape hatch, until people submit PRs to packages to help with type-stability. Likely an ENV var that turns your package off, or at least changes to warnings.

I think your package isn’t a prototype by now, should just work, would you ideally say it should be part of Base…? At least document its existence in Julia docs?

In Julia 2.0 possibly type-stable could be the default, though type-_in_stability has its uses, then a/your macro to allow it. Possibly the new default should be at package/module level, i.e. for only certain packages (a certain 2.0 or new enough package, or a setting in Project.toml) and/or in debug/REPL mode?

Even better then checking for type-instability would be fixing it automatically… E.g. 0.0 → zero(x) and 1.0 to one(x), it’s just hard to know what that x should be… maybe it isn’t in some cases?

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [May 28, 2024, 6:43pm UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/13 "2024-05-28T18:43:40Z")

</div>

> [@MilesCranmer](#):
>
> Do you mean that all `@stable` in all packages could be enabled/disabled with a single [Preferences.jl](https://juliahub.com/ui/Packages/General/Preferences) setting (sort of like it’s a compiler option), overriding any choice of `enable`?

Preferences.jl uses your environment stack. So you can apply settings depot-wide or have them apply to a specific project. You can have this setting be in a LocalPreferences.toml or your Project.toml.

```julia
const enable_default = @load_preference("enable", false)

```

I suppose the question then is what should the default be. I contend the default should be `false` so when deployed to the user, who has no Preferences.jl setting, then the checks will be disabled. Meanwhile, the developer could have a LocalPreferences.toml in the package environment or in a test environment where this is enabled.

---

<div class="post-metadata">

**Author:** ![alfaromartino](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alfaromartino/32/52986_2.png) [@alfaromartino](https://discourse.julialang.org/u/alfaromartino)\
**Post date:** [May 28, 2024, 6:55pm UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/14 "2024-05-28T18:55:44Z")

</div>

> [@MilesCranmer](#):
>
> ```julia
> Inferred to be `Union{Float64, Int64}`,
> which is not a concrete type.
> 
> ```

Just a quibble. Is the phrase “which is not a concrete type” in the error message applying to all cases ?

If that’s the case, it could be problematic. For instance, `Vector{Any}` is a concrete type.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [May 28, 2024, 7:45pm UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/15 "2024-05-28T19:45:02Z")

</div>

> [@mkitti](#):
>
> [Preferences.jl](https://juliahub.com/ui/Packages/General/Preferences) uses your environment stack. So you can apply settings depot-wide or have them apply to a specific project. You can have this setting be in a LocalPreferences.toml or your Project.toml.

Thanks. So I guess `dispatch_doctor_warnonly` and `dispatch_doctor_enable` make sense? Then you can set it for specific packages in your dependencies? (Is that how it works?)

> [@mkitti](#):
>
> I suppose the question then is what should the default be. I contend the default should be `false` so when deployed to the user, who has no [Preferences.jl](https://juliahub.com/ui/Packages/General/Preferences) setting, then the checks will be disabled. Meanwhile, the developer could have a LocalPreferences.toml in the package environment or in a test environment where this is enabled.

I think we can do both:

- If someone is using DispatchDoctor locally, like in a script, it would be nicer to have `@stable` work out of the box.
  - (I could see `@stable` being useful to Julia novices learning about performance gotchas – I wouldn’t want them to worry about LocalPreferences.toml yet)

- If someone uses DispatchDoctor in a library, then indeed it would be nicer to disable it by default. And because they are a package dev, they are also more comfortable with customizing macro options/Preferences, so we can put that on them!

To deal with both cases, I think the `enable` option in the macro should be treated as a _suggestion_. If you wrap your package like

```julia
module MyPackage
using DispatchDoctor
@stable enable=false begin

# Entire package code

end
end

```

then the stability checks will be disabled by default. The dev could turn them **on during testing** with `dispatch_doctor_enable => true` in the preferences, but otherwise they would be set to off. So downstream users wouldn’t need to worry about them (unless an advanced user chooses to set them via `LocalPreferences.toml`)

In code, it would look like:

```julia
should_enable = load_preference(
    calling_module, # __module__
    "dispatch_doctor_enable",
    enable # Initial option passed to macro
)

```

which would produce the final result for whether it should be turned on or off.

Thoughts?

> [@alfaromartino](#):
>
> Just a quibble. Is the phrase “which is not a concrete type” in the error message applying to all cases ?
> 
> If that’s the case, it could be problematic. For instance, `Vector{Any}` is a concrete type

Not sure I follow? It seems to work fine:

```julia
julia> Base.isconcretetype(Vector{Any})
true

julia> f() = Any[1, 2]; Test.@inferred f()
2-element Vector{Any}:
 1
 2

julia> @stable g() = Any[1, 2]; g()
2-element Vector{Any}:
 1
 2

```

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [May 28, 2024, 8:36pm UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/16 "2024-05-28T20:36:57Z")

</div>

Okay made a PR here: [Add preferences interface by MilesCranmer · Pull Request #14 · MilesCranmer/DispatchDoctor.jl · GitHub](https://github.com/MilesCranmer/DispatchDoctor.jl/pull/14)

> You might find it useful to _only_ enable `@stable` during unit-testing,  
> to have it check every function in a library, but not throw errors for  
> downstream users. For this, you can use the `default_mode` keyword to set the  
> default behavior:
> 
> ```julia
> module MyPackage
> using DispatchDoctor
> @stable default_mode="disable" begin
> 
> # Entire package code
> 
> end
> end
> 
> ```
> 
> This sets the default, but the mode is configurable  
> via [Preferences.jl](https://github.com/JuliaPackaging/Preferences.jl):
> 
> ```julia
> using MyPackage
> using Preferences
> 
> set_preferences!(MyPackage, "instability_check" => "error")
> 
> ```
> 
> which you can also set to be `"warn"` if you prefer.

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [May 29, 2024, 5:16am UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/17 "2024-05-29T05:16:54Z")

</div>

Very cool package!

> [@MilesCranmer](#):
>
> Code which is type stable should compile away the check:

I have not followed the performance optimization thread, so could you explain in terms accessible to a metaprogramming layperson how this is even possible? And whether we can be 100% certain that the check compiles away every time?

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [May 29, 2024, 6:04am UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/18 "2024-05-29T06:04:40Z")

</div>

> [@gdalle](#):
>
> I have not followed the performance optimization thread, so could you explain in terms accessible to a metaprogramming layperson how this is even possible?

So, because the Julia compiler infers return type of a function given the input types. All DispatchDoctor does is, for a function `f1`:

1. Puts `f1`’s body into a separate function definition, with an identical signature, but a different name. Let’s call it `f2`.
2. From the original function `f1`, it removes the original body, and inserts code that will checks the compiler-inferred type of `f2` given the _types_ of `args`.
3. `f1` runs `Base.isconcretetype` on that inferred type, and if false, throws an error.
4. Otherwise, `f1` calls `f2(args…)`, and returns the result.

So because the inference of `f2` and `isconcretetype` are in “type space”, it can do that at compile time. Thus, if things are type stable, Julia should just remove the error message from the code altogether.

Basically this if-statement’s first term only depends on input types:

> <https://github.com/MilesCranmer/DispatchDoctor.jl/blob/788284f8c8439f08f8bef5f8cbdccf478ae808fc/src/DispatchDoctor.jl#L290>

And if `type_instability(T)` evaluates to `false`, it should compile to

```julia
if false && ...
    error()
end

f2(args...)

```

and then we assume LLVM will remove that if statement.

> [@gdalle](#):
>
> And whether we can be 100% certain that the check compiles away every time?

Well, I don’t want to say 100%. I haven’t found an example otherwise but with the Julia compiler and LLVM I never really feel 100% confident about an optimization taking place or not. It “should” compile away that if statement, but people should share examples otherwise.

I guess we could make ourselves 100% confident if we turn the checker function into a `@generated` function, so that we can explicitly remove the if statement from the code. But I’m assuming the Julia compiler will do that for us.

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [May 29, 2024, 7:48am UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/19 "2024-05-29T07:48:40Z")

</div>

Thanks for the explanation! This is going straight into [ModernJuliaWorkflows](https://modernjuliaworkflows.github.io/)

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [May 29, 2024, 9:03am UTC](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837/20 "2024-05-29T09:03:14Z")

</div>

Awesome 🙂

* * *

By the way, does anybody have a workaround for using `@stable` directly on the top-level block of a Julia module?

I would like to do:

```julia
module MyPackage
@stable begin # Wrap entire package
  
# pkg code...

# with some reexports:
using Reexport: @reexport
@reexport using MySubmodule: A, B, C
  
end
end

```

However, for this, it says `@reexport` is undefined. I looked more into this and it seems macros aren’t allowed to have their definition in a regular block:

```julia
begin
    macro m(ex); ex; end
    @m 1
end

```

This gives the same error. (e.g., [Macros not imported within blocks](https://discourse.julialang.org/t/macros-not-imported-within-blocks/47009))

So, to this, my question is: how can I apply `@stable` to the top-level block of a module, from within the module itself?

Basically I want for

```julia
@stable begin

end

```

to get “merged” into the same block it sits in, rather than creating a new block.

[Next page](https://discourse.julialang.org/t/ann-dispatchdoctor-jl-offers-you-a-prescription-for-type-stability/114837.md?page=2)
