# Extensions, world age and generated function

**URL:** https://discourse.julialang.org/t/extensions-world-age-and-generated-function/135961
**Category:** General Usage
**Created:** [March 2, 2026, 5:01pm UTC](https://discourse.julialang.org/t/extensions-world-age-and-generated-function/135961 "2026-03-02T17:01:24Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![epilliat](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/epilliat/32/219946_2.png) [@epilliat](https://discourse.julialang.org/u/epilliat)
#### Post date: [March 2, 2026, 5:01pm UTC](https://discourse.julialang.org/t/extensions-world-age-and-generated-function/135961/1 "2026-03-02T17:01:25Z")

</div>

Hello everyone,

I’m writing a package with extensions and ran into a world age issue. The problem is the same as in [JuliaLang/julia#19942](https://github.com/JuliaLang/julia/issues/19942) and related to [this discourse thread](https://discourse.julialang.org/t/generated-functions-and-world-age/1867).

## Minimal example

```julia
function bar end

@generated function foo(::Val{x}) where x
    u = bar(x)
    return :($u)
end

bar(x::Integer) = x + 1

```

Let say `foo` is defined in the main package, and `bar(x::Integer)` is defined in an extension triggered by a dependency. This means that when a user does:

```julia
using MainPackage
using PackageThatTriggersExtension

```

the world age problem occurs at load time: the `@generated` body calls `bar` at specialization time, but the extension’s method is “too new.”

1. Is there a way to “finalize” extensions — i.e. run some code in the main package (that is the same for all extensions) each time an extension is loaded? In this case, that hook could force re-specialization of `foo`.

2. Alternatively, is there a way to disable precompilation of a specific `@generated` function, so that it specializes lazily at first call (by which time all extensions are loaded)?

For now, my workaround is to define `bar(::SomeTypeRelatedToExt, x::Integer)` in each extension. There are other workarounds too, but I’d like to know if there’s a clean way to do this in Julia.

---

<div class="post-metadata">

### Author: ![Keno](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/keno/32/285_2.png) [@Keno](https://discourse.julialang.org/u/Keno)
#### Post date: [March 2, 2026, 8:26pm UTC](https://discourse.julialang.org/t/extensions-world-age-and-generated-function/135961/2 "2026-03-02T20:26:43Z")

</div>

It would be in principle legal to run `bar` in the world age of the caller, as long as the generated functions sets the appropriate edges and bounds. That said, there isn’t a lot of supporting infrastructure to make writing that code easy. That said, in such a case, it would also be equivalent to use `assume_effects` (if necessary, it is not in your example) on `bar` to allow the compiler to perform this memoization automatically and that solution would be preferred.

---

<div class="post-metadata">

### Author: ![epilliat](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/epilliat/32/219946_2.png) [@epilliat](https://discourse.julialang.org/u/epilliat)
#### Post date: [March 2, 2026, 9:51pm UTC](https://discourse.julialang.org/t/extensions-world-age-and-generated-function/135961/3 "2026-03-02T21:51:39Z")

</div>

Thanks! Unfortunately `@assume_effects :foldable`/`:total` didn’t work in my case (device query + string pattern matching).

I ended up with this self-memoizing pattern:

```julia
function foo(::Val{x}) where x
    result = bar(x)
    @eval foo(::Val{$x}) = $result
    return Base.invokelatest(foo, Val(x))
end

```

Now I do not get precompilation problem anymore since it is @eval’ed at first call…  
Is this considered clean Julia? Or can I get some performance problem for some obscure reason

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [March 2, 2026, 10:59pm UTC](https://discourse.julialang.org/t/extensions-world-age-and-generated-function/135961/4 "2026-03-02T22:59:39Z")

</div>

This problem doesn’t require precompilation or `foo` being specialized before defining `bar(x::Integer)` (method definitions alone can’t be specialized, so there isn’t an obvious place it happens in your minimal example, either); it happens if I paste it in the REPL, where `foo` is only called at the end and specialized for the first time:

```julia-auto
julia> function bar end
bar (generic function with 0 methods)

julia> @generated function foo(::Val{x}) where x
           u = bar(x)
           return :($u)
       end
foo (generic function with 1 method)

julia> bar(x::Integer) = x + 1
bar (generic function with 1 method)

julia> foo(Val(1))
ERROR: MethodError: no method matching bar(::Int64)
The applicable method may be too new: running in world age 38708, while current world is 38709.

```

Generated functions are fundamentally stuck in the world age present during their method definition, as documented on the Manual page Metaprogramming\>Generated functions:

> When defining generated functions, there are five main differences to ordinary functions:  
> …  
> 4. Generated functions are only permitted to call functions that were defined _before_ the definition of the generated function. (Failure to follow this may result in getting `MethodErrors` referring to functions from a future world-age.)

Effectively, generated functions don’t experience method invalidation like normal functions (introduced by fixing Issue #265). Your example put into the REPL is nearly identical to issue [Issue #23223](https://github.com/JuliaLang/julia/issues/23223), just uses `::Type{T}` instead of `::Val{x}`. It’s pointed out there that:

> Method source code (“ages”) is not allowed to depend on data. This is fundamental to the design of the fix for #265. I realize that it’s weird to think of the execution of code as data, but welcome to LISP 🙂  
> …  
> It’s just important to realize that they are part of the compiler (and thus are data), not the runtime (and thus are not similar to methods). As such, it is strictly impossible (by definition) for them to be more capable than a normal function. They are, however, capable of implementing optimizations that are not currently part of the compiler, or that aren’t worthwhile to code for generically. It would be possible to define them to be part of the runtime, but then it would be invalid for the compiler to inspect them, making there existence as an annotation pointless (because they would be strictly inferior to not annotating them at all).

I don’t know how the line between compiler+data and runtime+methods are being drawn (for instance, constants being introduced to world age in v1.12 means that I could colloquially make global data that methods depend on and are invalidated by), but it’s a deep enough characteristic that users can’t do anything.

> [@epilliat](#):
>
> is there a way to disable precompilation of a specific `@generated` function, so that it specializes lazily at first call (by which time all extensions are loaded)

It’s not clear what you want to accomplish. Precompilation is intended to cache things we can use long-term, but you want it to depend on optional extensions, the combination of which will vary in routine usage.

> [@epilliat](#):
>
> my workaround is to define `bar(::SomeTypeRelatedToExt, x::Integer)` in each extension.

Regardless of generated functions, extensions are intended to produce methods that mix functions and types from all trigger packages, not to optionally load methods that invalidate existing behavior in just one function. That can be accomplished already with a package that directly commits type piracy (say `PackageThatTriggersExtension` defines `bar(x::Integer)`), and that’s known bad practice.

---

<div class="post-metadata">

### Author: ![Keno](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/keno/32/285_2.png) [@Keno](https://discourse.julialang.org/u/Keno)
#### Post date: [March 3, 2026, 12:22am UTC](https://discourse.julialang.org/t/extensions-world-age-and-generated-function/135961/5 "2026-03-03T00:22:39Z")

</div>

> [@epilliat](#):
>
> Thanks! Unfortunately `@assume_effects :foldable`/`:total` didn’t work in my case (device query + string pattern matching).

Try adding :effect\_free.

---

<div class="post-metadata">

### Author: ![epilliat](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/epilliat/32/219946_2.png) [@epilliat](https://discourse.julialang.org/u/epilliat)
#### Post date: [March 4, 2026, 8:44am UTC](https://discourse.julialang.org/t/extensions-world-age-and-generated-function/135961/6 "2026-03-04T08:44:48Z")

</div>

Unfortunately none of the `@assume_effects` annotations (including `:total` and `:effect_free`) worked in my case since `bar` involves too complex stuff so that, I guess, the compiler cannot proofs it is ok. I ended up going with `@eval` to rewrite the method on first call, and warming up the cache in each backend extension’s ` __init__ `. Works perfectly even in the test environment with no warnings.
