Julia: function inside a struct and method constructor

Viewed 1512

What is the correct way to store a function in a struct constructor? And retrieve it? And change its parameters?

I wrote some code back in version 0.4 to 0.5, which unsurprisingly no longer works. In words: I have a struct-cum-method named Model in which I define parameters and functional forms. And a similarly structured Solution in which I solve instances of the model. My purpose is to make multiple simulations of the model for different sets of parameters and functional forms. The code below is part of a module inside a package. I don't have a good handle on how to deal with the function type in Julia 1.6 (something like the code below used to work).

# Non-Parametric version of struct + outer method constructor
# Model parameters and functions
struct Model
    f::Function
    p::Float64
    n::Int64
end
function Model(; 
    f::Function = x -> x + p,
    p::Float64 = 2.0,
    n::Int64 = 4
    )
    Model(f, p, n)
end

This is the output of Model():

julia> m = Model()
Model(var"#2#4"(), 2.0, 4)

julia> Model(p = 1.0)
Model(var"#3#5"(), 1.0, 4)

julia> m.f
#2 (generic function with 1 method)

julia> m.p
2.0

julia> m.n
4

julia> Model(f = x -> x - p)
Model(var"#15#16"(), 2.0, 4)


julia> m.f(1.0)
ERROR: UndefVarError: p not defined
Stacktrace:
 [1] (::var"#2#4")(x::Float64)
   @ Main ./REPL[2]:2
 [2] top-level scope
   @ REPL[4]:1

I'd be grateful for pointers on where the code goes wrong and how to fix it. If at all recommended, I'd like a parametric struct.

1 Answers

You need to use Base.@kwdef or an @with_kw equivalent from the Parameters package (I prefer the latter since it provides nicer formatting for the console)

Base.@kwdef struct Model
    p::Float64 = 2.0
    n::Int64 = 4
    f::Function = x -> x + p
end

This now can be used such as:

julia> Model(p=7).f(11)
18

Regarding solution you should separate the actual solution structure from the constructor. Hence you will have a function solve(m::Model) (or solve! if m is mutated in the process) that should yields a Solution object.

For creating the Solution object use the same pattern as above.

Related