# AD over runtime-selected fields in nested structs — design patterns?

**URL:** <https://discourse.julialang.org/t/ad-over-runtime-selected-fields-in-nested-structs-design-patterns/136882>\
**Category:** Machine Learning\
**Tags:** forwarddiff\
**Created:** [April 25, 2026, 12:52pm UTC](https://discourse.julialang.org/t/ad-over-runtime-selected-fields-in-nested-structs-design-patterns/136882 "2026-04-25T12:52:53Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![stevenhughes](https://avatars.discourse-cdn.com/v4/letter/s/4da419/32.png) [@stevenhughes](https://discourse.julialang.org/u/stevenhughes)\
**Post date:** [April 25, 2026, 12:52pm UTC](https://discourse.julialang.org/t/ad-over-runtime-selected-fields-in-nested-structs-design-patterns/136882/1 "2026-04-25T12:52:53Z")

</div>

We have a framework where users define models as nested structs and declare at runtime which fields are optimization variables. The framework then needs to differentiate constraints/objectives with respect to those selected fields using ForwardDiff.

The challenge: kernels take the top-level struct, but ForwardDiff needs `Dual` to propagate through only the selected field — which lives somewhere deep in the struct graph. I am struggling with how to go about this. I have a few approaches I have prototyped shown below. Am I on the right track? Is there a better way to go about this? Thanks in advance for any thoughts or alternatives.

**Approach 1: Accessors.jl + independent type parameters**

Give each potentially-differentiable field its own type parameter, use `@set` to surgically inject `Dual`:

```julia
struct Foo{TA<:Real, TB<:Real}
    a::TA
    b::TB
end

ForwardDiff.derivative(x0) do x
    foo_dual = @set foo.a = x
    f(foo_dual)
end

```

Pro: Call sites unchanged, struct evolves naturally.  
Con: Every differentiable field needs its own type parameter — proliferates on complex models.

\*\*Approach 2: Kernels take field values, not structs

Functions take values extracted at the call site and data on structs does not need to be converted to Dual.

```julia
kernel(a, b) = ...
kernel(foo.a, foo.b)

ForwardDiff.derivative(x -> kernel(x, foo.b), foo.a)

```

Pro: Structs need no type parameters.  
Con: Adding a field to a struct requires updating all kernel signatures — loses OO ergonomics. Maintenance nightmare.

\*\* Question

Is there a cleaner Julia-idiomatic solution? Specifically: how do you differentiate with respect to a runtime-selected subset of fields in a nested struct without either proliferating type parameters, breaking struct-based dispatch, or rebuilding large structs for every AD permutation? Are there better solutions I am missing? Thanks!

---

<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:** [April 25, 2026, 5:32pm UTC](https://discourse.julialang.org/t/ad-over-runtime-selected-fields-in-nested-structs-design-patterns/136882/2 "2026-04-25T17:32:07Z")

</div>

AFAIK, your “approach 1” is the common way to go.

---

<div class="post-metadata">

**Author:** ![devel-chm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/devel-chm/32/3572_2.png) [@devel-chm](https://discourse.julialang.org/u/devel-chm)\
**Post date:** [April 25, 2026, 6:58pm UTC](https://discourse.julialang.org/t/ad-over-runtime-selected-fields-in-nested-structs-design-patterns/136882/3 "2026-04-25T18:58:38Z")

</div>

> [@stevenhughes](#):
>
> Give each potentially-differentiable field its own type parameter, use `@set` to surgically inject `Dual`:

What is `@set` , which package provides it?

-chm

---

<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:** [April 25, 2026, 8:27pm UTC](https://discourse.julialang.org/t/ad-over-runtime-selected-fields-in-nested-structs-design-patterns/136882/4 "2026-04-25T20:27:55Z")

</div>

Accessors.jl

It lets you use mutation-like syntax to update immutable structs.

---

<div class="post-metadata">

**Author:** ![stevenhughes](https://avatars.discourse-cdn.com/v4/letter/s/4da419/32.png) [@stevenhughes](https://discourse.julialang.org/u/stevenhughes)\
**Post date:** [April 26, 2026, 12:10pm UTC](https://discourse.julialang.org/t/ad-over-runtime-selected-fields-in-nested-structs-design-patterns/136882/5 "2026-04-26T12:10:49Z")

</div>

Thanks. Accessors.jl and @set seems like the standard approach, but before I build on top of it I wanted a sanity check.
