Modify array of functions in a mutable struct

I am trying to create a struct that contains functions, which will be used to construct a set of differential equations. The complication is that I want to be able to modify the struct’s functions after evaluating the solution of the ODE of these functions. Below is a minimal working example of what I mean:

mutable struct Foo
    farr :: Array{Function, 1} # array of functions used to construct a system of ODEs
end

function initfoo() # create "basic" functions
    vs = Array{Function, 1}(undef, 2)
    f(x) = x^2
    g(x) = 1
    vs[1] = f
    vs[2] = g
    Foo(vs) # return new Foo object
end

foo = initfoo() # create Foo object

# Test the original functions
foo.farr[1](2) # == 4
foo.farr[2](2) # == 1 # these work

# Now I want to change the functions
foo.farr[1] = x -> foo.farr[1](x) * (1 + x)
foo.farr[1](1) # this results in a StackOverflowError

It seems I am doing something wrong when I modify the functions in the struct. For my application it is important that I “append” to the original function in the struct. Does anybody know how to fix this?

old = foo.farr[1]
foo.farr[1] = x -> old(x) * (1+x)
1 Like

I just tried this and it still gave the stack overflow error (on evaluation, not on assignment). I also tried copying the function before re-assigning, but alas that did not work either…

julia> vs = Array{Function, 1}(undef, 2)
2-element Array{Function,1}:
 #undef
 #undef

julia> vs[1] = x -> x^2
#4465 (generic function with 1 method)

julia> vs[1](2)
4

julia> old = vs[1]
#4465 (generic function with 1 method)

julia> vs[1] = x -> old(x) * (1+x)
#4467 (generic function with 1 method)

julia> vs[1](2)
12
1 Like

Scratch that, it works! Thank you very much!!

This is more generic and captures the old function in a closure:

julia> function nextfunc(old,new)
         return x -> new(old(x),x)
         end
nextfunc (generic function with 1 method)

julia> vs[1] = x -> x^2
#4471 (generic function with 1 method)

julia> vs[1] = nextfunc(vs[1],(o,x)->o*(1+x))
#4469 (generic function with 1 method)

julia> vs[1](2)
12
1 Like

Thanks :slight_smile: This will make downstream code prettier I think!