# Recompile generated function when methods get defined

**URL:** <https://discourse.julialang.org/t/recompile-generated-function-when-methods-get-defined/99089>\
**Category:** General Usage\
**Created:** [May 18, 2023, 11:26pm UTC](https://discourse.julialang.org/t/recompile-generated-function-when-methods-get-defined/99089 "2023-05-18T23:26:01Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [May 18, 2023, 11:26pm UTC](https://discourse.julialang.org/t/recompile-generated-function-when-methods-get-defined/99089/1 "2023-05-18T23:26:02Z")

</div>

Normally, generated functions can only use methods defined earlier:

```julia
julia> f(x) = 1
julia> @generated g(x...) = f(x...)
julia> f(x, y) = 2

julia> g(1)
1
julia> g(1, 1)
ERROR: MethodError: no method matching f(::Type{Int64}, ::Type{Int64})
The applicable method may be too new: running in world age 33465, while current world is 33466.

```

How can I make Julia recompile `g` whenever `f` changes (new `f` methods get defined)? That’s definitely possible, [Tricks.jl](https://github.com/oxinabox/Tricks.jl) does this stuff, but I couldn’t really understand nor utilize code from that package so that `g` works in the above example.

Can you please advice on how to achieve that? I guess some compilation backedges need to be inserted, but couldn’t adapt Tricks code for such a case myself.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 18, 2023, 11:39pm UTC](https://discourse.julialang.org/t/recompile-generated-function-when-methods-get-defined/99089/2 "2023-05-18T23:39:33Z")

</div>

It’s compilicated. You basically need to turn the generated expression into a CodeInfo, and then attach backedges manually to that codeinfo

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [May 18, 2023, 11:53pm UTC](https://discourse.julialang.org/t/recompile-generated-function-when-methods-get-defined/99089/3 "2023-05-18T23:53:32Z")

</div>

Btw, is there a reason this behavior isn’t the default? Regular functions get invalidated when relevant methods appear, why not do the same for generated?

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 18, 2023, 11:59pm UTC](https://discourse.julialang.org/t/recompile-generated-function-when-methods-get-defined/99089/4 "2023-05-18T23:59:30Z")

</div>

Here’s an example of doing it to your `g` function. It should work on current versions of julia, but would need some tweaks to work with the current `master` due to a change in how generated functions interact with some internals

```julia
using Core: SimpleVector, svec, CodeInfo
using Core.Compiler: MethodInstance, method_instances

function expr_to_codeinfo(m::Module, argnames, spnames, sp, e::Expr)
    lam = Expr(:lambda, argnames,
               Expr(Symbol("scope-block"),
                    Expr(:block,
                         Expr(:return,
                              Expr(:block,
                                   e,
                                   )))))
    ex = if spnames === nothing || isempty(spnames)
        lam
    else
        Expr(Symbol("with-static-parameters"), lam, spnames...)
    end

    # Get the code-info for the generatorbody in order to use it for generating a dummy
    # code info object.
    ci = ccall(:jl_expand_and_resolve, Any, (Any, Any, SimpleVector), ex, m, svec(sp...))
    @assert ci isa CodeInfo "Failed to create a CodeInfo from the given expression. This might mean it contains a closure or comprehension?\n Offending expression: $e"
    ci
end

```

```julia
@generated function g(args...) 
    ex = :(f($(args...)))
    ci = expr_to_codeinfo(@ __MODULE__ (), [Symbol("#self#"), (Symbol(:arg, i) for i ∈ 1:length(args))...], [], (), ex)
    ci.edges = MethodInstance[]
    for mi ∈ method_instances(f, Tuple{args...})
        push!(ci.edges, mi)
    end
    return ci
end

```

and then we see it properly recompile as we add methods

```julia
julia> f(x) = 1
f (generic function with 1 method)

julia> g(1)
1

julia> f(x, y) = 2
f (generic function with 2 methods)

julia> g(1, 1)
2

```

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [May 19, 2023, 12:20am UTC](https://discourse.julialang.org/t/recompile-generated-function-when-methods-get-defined/99089/5 "2023-05-19T00:20:18Z")

</div>

Thanks for a nice easy-to-use recipe! However, this isn’t equivalent to my `g` function: mine executes `f` compiletime, yours puts its call into runtime.  
Difference clearly visible with

```julia
julia> f(x) = :(1+1)
julia> f(x, y) = :(2+2)

```

Replacing `ex = :(f($(args...)))` with `ex = f(args...)` in your example doesn’t help: MethodErrors remain.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 19, 2023, 12:59am UTC](https://discourse.julialang.org/t/recompile-generated-function-when-methods-get-defined/99089/6 "2023-05-19T00:59:13Z")

</div>

Oh, you want to recompile the generator, yeah I missed that. Unfortunately, due to a limitation I don’t quite understand, the backedge insertion thing only works in the function actually appears in the body, it won’t work if you call the function at comptime.

I think this issue is related: [Generator output with explicit edges not always invalidated · Issue #34962 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/34962)

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [May 19, 2023, 8:32am UTC](https://discourse.julialang.org/t/recompile-generated-function-when-methods-get-defined/99089/7 "2023-05-19T08:32:49Z")

</div>

Doesn’t `Tricks` recompile the generator somehow? Eg, its `hasmethod` changes from compile-time `false` to compile-time `true` when a method is defined. So, seems possible…
