# Mutable struct and function as parameters. Why can't the function access the new values?

**URL:** <https://discourse.julialang.org/t/mutable-struct-and-function-as-parameters-why-cant-the-function-access-the-new-values/101915>\
**Category:** General Usage\
**Tags:** struct\
**Created:** [July 22, 2023, 12:08am UTC](https://discourse.julialang.org/t/mutable-struct-and-function-as-parameters-why-cant-the-function-access-the-new-values/101915 "2023-07-22T00:08:05Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![BMval](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bmval/32/7647_2.png) [@BMval](https://discourse.julialang.org/u/BMval)\
**Post date:** [July 22, 2023, 12:08am UTC](https://discourse.julialang.org/t/mutable-struct-and-function-as-parameters-why-cant-the-function-access-the-new-values/101915/1 "2023-07-22T00:08:05Z")

</div>

Mutable struct and function as parameters. Why can’t the function access the new values?

Both calls to p.f() return the same value, 2.0, despite the new value of x

```julia
@with_kw mutable struct Params
     x = 1.0
     f::Function = () -> 2*x 
 end
p=Params();
p.f()
p.x=10
p.x
p.f()

```

---

<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:** [July 22, 2023, 12:34am UTC](https://discourse.julialang.org/t/mutable-struct-and-function-as-parameters-why-cant-the-function-access-the-new-values/101915/2 "2023-07-22T00:34:34Z")

</div>

Looking at the `@macroexpand`, something like this happens:

```julia
julia> mutable struct Xf
         x::Float64
         f::Function
       end

julia> foo(; x = 1.0, f = (() -> 2*x)) = Xf(x, f)
foo (generic function with 1 method)

julia> xf = foo()
Xf(1.0, var"#22#24"{Float64}(1.0))

julia> xf.x, xf.f()
(1.0, 2.0)

julia> xf.x = 10; xf.x, xf.f()
(10.0, 2.0)

```

The anonymous function captured the `x` in the `foo` function; in other words they share that variable. But the `Xf` constructor does not share the variable `x`, the call `Xf(x, f)` just has the variables pass their instances to `Xf`’s own local variables. The `Xf.x` field is thus independent of the captured variable `x`. It’s an understandable confusion given how closures work in function scopes, but despite how the macro makes it look, field definitions aren’t variables that could be captured by inner constructors.

Incidentally, the order of the keyword arguments and thus your fields is important for successful capturing:

```julia
julia> foo(;f = (() -> 2*x), x = 1.0) = Xf(x, f)
foo (generic function with 1 method)

julia> xf = foo() # xf.f didn't bother capturing anything
Xf(1.0, var"#12#14"())

julia> xf.f()
ERROR: UndefVarError: x not defined

```

To accomplish what you seem to be going for, you could do this:

```julia
mutable struct Params
  x::Float64
end

(p::Params)() = 2*p.x

p = Params(1.0)
p() # 2.0
p.x = 10
p() # 20.0

# if you rather not have p itself be callable
f(p::Params) = 2*p.x # do f(p) instead of p.f()

```

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [July 22, 2023, 4:11am UTC](https://discourse.julialang.org/t/mutable-struct-and-function-as-parameters-why-cant-the-function-access-the-new-values/101915/3 "2023-07-22T04:11:06Z")

</div>

The `x` that is captured is the keyword from the constructor. You could set it up this way though:

```julia
mutable struct Params
    x::Float64
    f::Function
    function Params(x = 1.0)
        p = new(x)
        p.f = ()->p.x*2
        return p
   end
end

julia> mutable struct Params
           x::Float64
           f::Function
           function Params(x = 1.0)
               p = new(x)
               p.f = ()->p.x*2
               return p
          end
       end

julia> p = Params(1.5)
Params(1.5, var"#7#8"{Params}(Params(#= circular reference @-2 =#)))

julia> p.f()
3.0

julia> p.x = 2
2

julia> p.f()
4.0

```

Making `Params` a functor like Benny suggested is probably better though.
