# Help understanding non-mutating function in Lux.Training

**URL:** <https://discourse.julialang.org/t/help-understanding-non-mutating-function-in-lux-training/133137>\
**Category:** Machine Learning\
**Tags:** question\
**Created:** [October 14, 2025, 11:02am UTC](https://discourse.julialang.org/t/help-understanding-non-mutating-function-in-lux-training/133137 "2025-10-14T11:02:37Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![IBArbitrary](https://avatars.discourse-cdn.com/v4/letter/i/9de053/32.png) [@IBArbitrary](https://discourse.julialang.org/u/IBArbitrary)\
**Post date:** [October 14, 2025, 11:02am UTC](https://discourse.julialang.org/t/help-understanding-non-mutating-function-in-lux-training/133137/1 "2025-10-14T11:02:37Z")

</div>

The `Training.apply_gradient` non-mutating function is implemented as below in `Lux.jl`:

```julia
function apply_gradients(ts::TrainState, grads)
    optimizer_state, ps = Optimisers.update(ts.optimizer_state, ts.parameters, grads)
    @set! ts.parameters = ps
    @set! ts.optimizer_state = optimizer_state
    @set! ts.step = ts.step + 1
    return ts
end

```

The way I understand is, `@set!` modifies the struct in place. But how does it still behave as a non-mutating function (the output of the function is the updated `ts`, but the `ts` passed into the function remains unchanged)?

---

<div class="post-metadata">

**Author:** ![avikpal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/avikpal/32/6550_2.png) [@avikpal](https://discourse.julialang.org/u/avikpal)\
**Post date:** [October 14, 2025, 6:36pm UTC](https://discourse.julialang.org/t/help-understanding-non-mutating-function-in-lux-training/133137/2 "2025-10-14T18:36:49Z")

</div>

See [Introduction · Setfield.jl](https://jw3126.github.io/Setfield.jl/dev/intro/#Under-the-hood). `@set!` doesn’t mutate the struct, instead it updates the struct field → creates a new struct and then updates the variable `ts` to reference the newly created struct.
