# If @generated branch selection

**URL:** <https://discourse.julialang.org/t/if-generated-branch-selection/137067>\
**Category:** General Usage\
**Created:** [May 10, 2026, 4:11pm UTC](https://discourse.julialang.org/t/if-generated-branch-selection/137067 "2026-05-10T16:11:38Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![cshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cshen/32/217287_2.png) [@cshen](https://discourse.julialang.org/u/cshen)\
**Post date:** [May 10, 2026, 4:11pm UTC](https://discourse.julialang.org/t/if-generated-branch-selection/137067/1 "2026-05-10T16:11:38Z")

</div>

Hello,

I was wondering what are the heuristics (if any) that the compiler uses to decide whether to use the @generated branch instead of the normal branch. The docs remain a little bit vague and only talk about this as a performance optimization, but in a trimming world taking the @generated branch or not might mean being able to compile vs not.

For example, say you have a `@generated` function. It’s a pretty heavy function and the first compilation takes quite a while, but it’s what makes it possible to actually make the verifier happy.

It’s not a performance sensitive function, and when used in a REPL, it would be more than fine to just use dynamic dispatch and don’t incur in the compilation time of the @generated function.

If I were to change that function to an `if @generated` body, do I get the best of both worlds:

- `@generated` during trimming, and dynamic dispatch in the REPL

or the worst of both:

- dynamic during trimming and `@generated` in the REPL?

a mix of both? Is this something that can be relied upon?

Thanks

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [May 10, 2026, 8:00pm UTC](https://discourse.julialang.org/t/if-generated-branch-selection/137067/2 "2026-05-10T20:00:37Z")

</div>

I think you are confusing concepts here but I can’t quite identify what you are mixing up. Perhaps you could write some code (doesn’t need to work/run) to clarify what scenario is unclear to and what you would like to have instead?

`@generated` itself has not much to do with dispatch. A `@generated` function simply creates the actual function body via code the first time it runs (for some specific signature). There are some more details to it but this is the bottomline.

---

<div class="post-metadata">

**Author:** ![dawbarton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dawbarton/32/215461_2.png) [@dawbarton](https://discourse.julialang.org/u/dawbarton)\
**Post date:** [May 10, 2026, 8:16pm UTC](https://discourse.julialang.org/t/if-generated-branch-selection/137067/3 "2026-05-10T20:16:00Z")

</div>

I think the poster is referring to the use of `if @generated` inside a generated function - see [optionally generated functions](https://docs.julialang.org/en/v1/manual/metaprogramming/#Optionally-generated-functions) in the manual. Unfortunately, the documentation doesn’t make it clear when it is actually used.

---

<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:** [May 10, 2026, 8:49pm UTC](https://discourse.julialang.org/t/if-generated-branch-selection/137067/4 "2026-05-10T20:49:28Z")

</div>

The non-`@generated` branch does not imply anything about dynamic dispatch (of multimethods), it’s just the behavior of normal generic function bodies without `@generated` metaprogramming. The `@generated` branch also does not guarantee a performance optimization; “can achieve high efficiency” does not imply it must. I could easily write a `@generated` branch expression that is less efficient (and with no multiple methods here to dispatch):

```julia-auto
julia> begin
       foo() = if @generated; :(Libc.systemsleep(2); 1) else 1 end
       @time foo()
       @code_llvm foo()
       end
  2.023341 seconds (2.62 k allocations: 125.938 KiB, 0.47% compilation time)
; Function Signature: foo()
; @ REPL[18]:2 within `foo`
; Function Attrs: uwtable
define i64 @julia_foo_1742() #0 {
top:
; ┌ @ REPL[18]:2 within `macro expansion`
; │┌ @ libc.jl:164 within `systemsleep`
    call x86_stdcallcc void @jlplt_Sleep_1746_got.jit(i32 2000)
; │└
   ret i64 1
; └
}

```

> [@cshen](#):
>
> Is this something that can be relied upon?

No, which is one of the few things the docs does clarify:

> However, which implementation is used depends on compiler implementation details, so it is essential for the two implementations to behave identically.

The compiler is free to change with any patch. Julia could theoretically be implemented without a compiler at all, in which case `@generated` function calls would be a nightmare of runtime `Expr` processing and `eval`.

Presumably, your concern with trimming is about the sentences:

> Typically, Julia is able to compile “generic” versions of functions that will work for any arguments, but with generated functions this is impossible. This means that programs making heavy use of generated functions might be impossible to statically compile.

At first glance, that doesn’t seem plausible. JuliaC’s trimming is primarily intended to support statically dispatched programs, which ought to provide the “static” types to normally compile `@generated` functions, prior to trimming. My _guess_ is that “generic versions” refers to non-monomorphic compilation e.g. `@nospecialize`, in which case `@generated` function calls would lack information at compile-time. But I wouldn’t expect that to work with trimming, and the docs don’t actually say what optionally generated functions can be good for. I’ve seen a few cases of devs actually giving up on them because the reference implementation’s compiler chose a slow non-`@generated` branch instead of just being a niche fallback. I bet they also wished they knew more about the compiler heuristics beforehand.

---

<div class="post-metadata">

**Author:** ![cshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cshen/32/217287_2.png) [@cshen](https://discourse.julialang.org/u/cshen)\
**Post date:** [May 11, 2026, 8:20am UTC](https://discourse.julialang.org/t/if-generated-branch-selection/137067/5 "2026-05-11T08:20:54Z")

</div>

You’re right, the dynamic dispatch implication is just my actual use case leaking through the description.  
Thanks for clarifying. After some extra thought, probably the better approach is mimicking rust’s features with `@static` and Preferences.jl to manually specify which version is compiled; instead of trying to rely on compiler heuristics. Something like:

```julia-auto
function myfunc(...)
    @static if juliac
        _myfunc_gen()
    else
        normal body
    end
end

```

---

<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:** [May 11, 2026, 7:24pm UTC](https://discourse.julialang.org/t/if-generated-branch-selection/137067/6 "2026-05-11T19:24:26Z")

</div>

I don’t think you would even need `@static if`, let alone embedded inside methods. Unless there’s some JuliaC-dependent expression that can’t survive to macro-expansion in non-JuliaC contexts, you can just conditionally define a `@generated` method or a normal method in the global scope:

```julia-auto
if juliac()
  @generated function myfunc(#=arguments=#)
    #=metaprogramming body, long compilation=#
  end
else
  function myfunc(#=same arguments=#)
    #=normal body, quick compilation=#
  end
end

```

But that’s the lesser issue. The main issue is the condition. There isn’t any documented Julia function that checks for JuliaC, let alone trimming, and it’s not actually the opposite of having a REPL. People routinely run scripts from the command line without firing up a REPL, so which definition happens in that case? `isinteractive()` is `true` for a REPL, but also third-party “interactive” contexts as generally implemented. Whatever the condition ends up being, you’d have to separately test and debug the implementations to never diverge in results, which is generally much harder to maintain than it appears.

Another issue is you’re also taking a choice away: trimmed binaries won’t opt into dynamic dispatch, but it’s very common to be willing to pay compilation costs for a faster run in the REPL. Typically that’s mitigated by package precompilation shifting the cost to environment instantiation instead of each Julia session, but that only works for call signatures you can confidently specify in advance and reuse in practice. You can still offer both versions as separate functions, though that would be annoying as callees to other functions that either have to diverge as well or take a function input.

---

<div class="post-metadata">

**Author:** ![adienes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/adienes/32/37459_2.png) [@adienes](https://discourse.julialang.org/u/adienes)\
**Post date:** [May 11, 2026, 7:33pm UTC](https://discourse.julialang.org/t/if-generated-branch-selection/137067/7 "2026-05-11T19:33:56Z")

</div>

> [@Benny](#):
>
> I could easily write a `@generated` branch expression that is less efficient (and with no multiple methods here to dispatch):

slightly tangential but note that this is not (I believe) a legal `if @generated` usage since the two branches have differing effects

---

<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 11, 2026, 7:43pm UTC](https://discourse.julialang.org/t/if-generated-branch-selection/137067/8 "2026-05-11T19:43:32Z")

</div>

> [@adienes](#):
>
> slightly tangential but note that this is not (I believe) a legal `if @generated` usage since the two branches have differing effects

There’s no documentation saying that the two branches need to have the same `Effects`. I agree that’s one way to read the documentation, but if it’s true, I’d argue that `if @generated` is basically impossible to safely use, because which `Effects` a piece of code has is not stable, and is the result of compiler knowledge.

---

<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:** [May 11, 2026, 7:48pm UTC](https://discourse.julialang.org/t/if-generated-branch-selection/137067/9 "2026-05-11T19:48:43Z")

</div>

Effects inference (again, internal compiler stuff) seems to agree on the effects being different, though I’m not exactly sure what `systemsleep` is doing:

```julia-auto
julia> Base.infer_effects(()->(Libc.systemsleep(2);1), ())
(!c,!e,!n,!t,!s,!m,!u,+o,!r)

julia> Base.infer_effects(()->1, ())
(+c,+e,+n,+t,+s,+m,+u,+o,+r)

julia> Base.infer_effects(foo, ())
(!c,!e,!n,!t,!s,!m,!u,+o,!r)

```

But section on optionally generated functions really does not say anything about effects. The preceding section on generated functions does say side effects shouldn’t occur, but it’s all about what the `@generated` method body does in the process of making the `Expr`, not what happens in the `Expr` itself. The distinction is worded very poorly though, so I’m not certain; the `@generated` function documentation is due for a rewrite, imo (what `then` block??)

---

<div class="post-metadata">

**Author:** ![adienes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/adienes/32/37459_2.png) [@adienes](https://discourse.julialang.org/u/adienes)\
**Post date:** [May 11, 2026, 7:50pm UTC](https://discourse.julialang.org/t/if-generated-branch-selection/137067/10 "2026-05-11T19:50:13Z")

</div>

my assertion was a (lossy) repetition of the information in this comment [Fix serialization when trimming by PatrickHaecker · Pull Request #61601 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/61601#issuecomment-4273706231), which is stated more precisely 🙂

---

<div class="post-metadata">

**Author:** ![cshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cshen/32/217287_2.png) [@cshen](https://discourse.julialang.org/u/cshen)\
**Post date:** [May 11, 2026, 8:54pm UTC](https://discourse.julialang.org/t/if-generated-branch-selection/137067/11 "2026-05-11T20:54:34Z")

</div>

Regarding the condition, I did try to use `Base.generating_output(false)` but that also turned out to not be really suitable. I ended up simply relying on a user defined preference through Preferences.jl, which seems to be the [general direction](https://github.com/JuliaLang/JuliaC.jl/pull/65) on how to recognize trimming state (not the user defined part, but the preference flag).  
And at that point, might as well use `@static`.

Lots of info here thought, thanks! it’s making me more and more scared of using `if @generated` now. Ensuring same effects seems like a nightmare to enforce and test.

---

<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 11, 2026, 10:50pm UTC](https://discourse.julialang.org/t/if-generated-branch-selection/137067/12 "2026-05-11T22:50:16Z")

</div>

> [@Benny](#):
>
> ```julia-auto
> if juliac()
> @generated function myfunc(#=arguments=#)
> #=metaprogramming body, long compilation=#
> end
> else
> function myfunc(#=same arguments=#)
> #=normal body, quick compilation=#
> end
> end
> 
> ```

Rather than this, I would do

```julia-auto
function myfunc(args...)
    if juliac_flag()
        myfunc_generated(args...)
    else
        myfunc_normal(args...)
    end
end

```

So long as the `juliac_flag()` function is a compile time constant, the compiler will only compile the branch that actually gets hit, and redefining the function will automatically cause it to switch:

```julia-auto
julia> @generated function foo(x)
           println("compiling foo !")
           :(x + 1)
       end;

julia> bar(x) = x - 1;

julia> toggle() = false;

julia> function foobar(x)
           if toggle()
               foo(x)
           else
               bar(x)
           end
       end;

julia> foobar(1)
0

```

Now redefining `toggle`:

```julia-auto
julia> toggle() = true;

julia> foobar(1)
compiling foo !
2

```

---

<div class="post-metadata">

**Author:** ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)\
**Post date:** [May 12, 2026, 12:29am UTC](https://discourse.julialang.org/t/if-generated-branch-selection/137067/13 "2026-05-12T00:29:52Z")

</div>

[Optional generators swallow errors · Issue #25707 · JuliaLang/julia](https://github.com/JuliaLang/julia/issues/25707) is still open (since 2018), so personally I steer away from `if @generated`.

---

<div class="post-metadata">

**Author:** ![adienes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/adienes/32/37459_2.png) [@adienes](https://discourse.julialang.org/u/adienes)\
**Post date:** [May 12, 2026, 1:07am UTC](https://discourse.julialang.org/t/if-generated-branch-selection/137067/14 "2026-05-12T01:07:36Z")

</div>

to be fair, that issue refers to when the code generation itself errors the else branch will be chosen. if the function is already implemented safely (in that the `if @generated` and the `else` branches are semantically identical) then that issue should never cause observable problems, only performance problems

---

<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:** [May 12, 2026, 4:39am UTC](https://discourse.julialang.org/t/if-generated-branch-selection/137067/15 "2026-05-12T04:39:30Z")

</div>

> [@Mason](#):
>
> So long as the `juliac_flag()` function is a compile time constant, the compiler will only compile the branch that actually gets hit

Leveraging world ages and recompilation is convenient for interactivity, but relying on compiler optimizations kind of goes against cshen’s preprocessor-like intent, as much as I have raised questions about it. The good news is even -O0 still does constant propagation and dead code elimination, so it could be fairly reliable in the current implementations even if not technically guaranteed.

The bad news is we have to really watch out for whether the flags are constants. For example, `isinteractive()` accesses a typed global internally, so it doesn’t work as one:

```julia-auto
julia> foo() = isinteractive() ? 1 : 2
foo (generic function with 1 method)

julia> @code_llvm foo() # runtime branch
; Function Signature: foo()
; @ REPL[1]:1 within `foo`
; Function Attrs: uwtable
define i64 @julia_foo_1359() #0 {
top:
; ┌ @ initdefs.jl:40 within `isinteractive`
   %is_interactive.checked = load atomic ptr, ptr getelementptr inbounds (ptr, ptr @"*Main.Base.is_interactive#1361.jit", i64 1) unordered, align 8
   %.not = icmp eq ptr %is_interactive.checked, null
   br i1 %.not, label %err, label %ok

err: ; preds = %top
   call void @ijl_undefined_var_error(ptr nonnull @"jl_sym#is_interactive#1362.jit", ptr nonnull @"jl_global#1363.jit")
   unreachable

ok: ; preds = %top
; └
  %is_interactive.checked.unbox = load i8, ptr %is_interactive.checked, align 1
  %.not1 = icmp eq i8 %is_interactive.checked.unbox, 0
  %common.ret.op = select i1 %.not1, i64 2, i64 1
  ret i64 %common.ret.op
}

```

But we can make our own internal constant:

```julia-auto
julia> const _isinteractive = isinteractive()
true

julia> foo() = _isinteractive ? 1 : 2
foo (generic function with 1 method)

julia> @code_llvm foo()
; Function Signature: foo()
; @ REPL[4]:1 within `foo`
; Function Attrs: uwtable
define i64 @julia_foo_1399() #0 {
top:
; @ REPL[4] within `foo`
  ret i64 1
}

julia> const _isinteractive = false
false

julia> @code_llvm foo() # recompiled
; Function Signature: foo()
; @ REPL[4]:1 within `foo`
; Function Attrs: uwtable
define i64 @julia_foo_1401() #0 {
top:
; @ REPL[4] within `foo`
  ret i64 2
}

```

Just to add if it’s not obvious already, `@static if` doesn’t allow this kind of recompilation because the `@static` macro call evaluates the conditions in the global scope and removes the branch from the input expression. In other words, there’s no constant condition left to compute at compile-time or track for recompilation.
