# Pass arguments to struct constructor

**URL:** https://discourse.julialang.org/t/pass-arguments-to-struct-constructor/91968
**Category:** New to Julia
**Created:** [December 21, 2022, 4:33pm UTC](https://discourse.julialang.org/t/pass-arguments-to-struct-constructor/91968 "2022-12-21T16:33:57Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![PatrickMcFarlane](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/patrickmcfarlane/32/50027_2.png) [@PatrickMcFarlane](https://discourse.julialang.org/u/PatrickMcFarlane)
#### Post date: [December 21, 2022, 4:33pm UTC](https://discourse.julialang.org/t/pass-arguments-to-struct-constructor/91968/1 "2022-12-21T16:33:57Z")

</div>

Hello,

I am working on code for an economic model. The solutions to the model are stored in arrays within an immutable struct. The dimensions of those arrays are drawn from another struct that holds hyperparameters for the numerical solution method (these govern the precision, domain, etc., of the solution).

So a highly simplified example of my solutions currently looks like:

```julia
@with_kw struct HHsol
    aP::Array{Float64,2} = fill(1.0,HYP.na, HYP.nz)
    cP::Array{Float64,2} = fill(1.0,HYP.na, HYP.nz)
end

```

where `HYP` is an instance of the struct containing the hyperparameters.

I’m doing simulations where I need to create a new instance of the solution structure but with different dimensions for the arrays drawn from a different instance of the hyperpameters structure. Is there a way that I can pass in the name of the hyperpameters structure to the solution constructor?

…something like:

```julia
@with_kw struct HHsol(HYPname)
    aP::Array{Float64,2} = fill(1.0,HYPname.na, HYPname.nz)
    cP::Array{Float64,2} = fill(1.0,HYPname.na, HYPname.nz)
end

```

The real solutions structure has many elements so that It would be cumbersome to have to directly specify the values rather than relying on default values when calling the constructor.

Thanks in advance for any advice!

---

<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: [December 21, 2022, 4:59pm UTC](https://discourse.julialang.org/t/pass-arguments-to-struct-constructor/91968/2 "2022-12-21T16:59:06Z")

</div>

You basically want to create your own macro here.

See [Metaprogramming · The Julia Language](https://docs.julialang.org/en/v1/manual/metaprogramming/)

```julia
@with_kw @fill_params HYPname struct HHsol
    aP::Array{Float64,2}
    cP::Array{Float64,2}
end

```

To start let’s create an expression:

```julia
julia> e =:(
       struct HHsol
           aP::Array{Float64,2}
           cP::Array{Float64,2}
       end)
:(struct HHsol
      #= REPL[14]:3 =#
      aP::Array{Float64, 2}
      #= REPL[14]:4 =#
      cP::Array{Float64, 2}
  end)

julia> typeof(e)
Expr

julia> e.head
:struct

julia> e.args
3-element Vector{Any}:
 false
      :HHsol
      quote
    #= REPL[14]:3 =#
    aP::Array{Float64, 2}
    #= REPL[14]:4 =#
    cP::Array{Float64, 2}
end

julia> e.args[2]
:HHsol

julia> e.args[3]
quote
    #= REPL[14]:3 =#
    aP::Array{Float64, 2}
    #= REPL[14]:4 =#
    cP::Array{Float64, 2}
end

```

We see that we primarily want to edit argument 3 which is a quote block.

```julia
julia> e2 = e.args[3]
quote
    #= REPL[14]:3 =#
    aP::Array{Float64, 2}
    #= REPL[14]:4 =#
    cP::Array{Float64, 2}
end

julia> typeof(e2)
Expr

julia> e2.head
:block

julia> e2.args
4-element Vector{Any}:
 :(#= REPL[14]:3 =#)
 :(aP::Array{Float64, 2})
 :(#= REPL[14]:4 =#)
 :(cP::Array{Float64, 2})

julia> e2.args[3]
:(#= REPL[14]:4 =#)

julia> e2.args[2]
:(aP::Array{Float64, 2})

julia> e2.args[2].head
:(::)

julia> e2.args[2].args
2-element Vector{Any}:
 :aP
 :(Array{Float64, 2})

```

Now we need to figure how we want to modify this expression. To do so we create the expression that we want and examine it first.

```julia
julia> target = :(aP::Array{Float64, 2} = fill(1.0,HYPname.na, HYPname.nz))
:(aP::Array{Float64, 2} = fill(1.0, HYPname.na, HYPname.nz))

julia> target.head
:(=)

julia> target.args
2-element Vector{Any}:
 :(aP::Array{Float64, 2})
 :(fill(1.0, HYPname.na, HYPname.nz))

```

We see that all we want to do is replace the `::` expression with a `:(=)` expression containing it. Let’s write a function to do that.

```julia
julia> function fill_individual_param(param_expr, s)
           Expr(
               :(=),
               param_expr,
               :(fill(1.0, $s.na, $s.nz))
           )
       end
fill_individual_param (generic function with 1 method)

julia> fill_individual_param(e2.args[2], :HYPname)
:(aP::Array{Float64, 2} = fill(1.0, ($(Expr(:escape, :HYPname))).na, ($(Expr(:escape, :HYPname))).nz))

julia> e2.args
4-element Vector{Any}:
 :(#= REPL[13]:3 =#)
 :(aP::Array{Float64, 2})
 :(#= REPL[13]:4 =#)
 :(cP::Array{Float64, 2})

julia> [isa(param, Expr) ? fill_individual_param(param, :HYPname) : param for param in e2.args]
4-element Vector{Any}:
 :(#= REPL[13]:3 =#)
 :(aP::Array{Float64, 2} = fill(1.0, ($(Expr(:escape, :HYPname))).na, ($(Expr(:escape, :HYPname))).nz))
 :(#= REPL[13]:4 =#)
 :(cP::Array{Float64, 2} = fill(1.0, ($(Expr(:escape, :HYPname))).na, ($(Expr(:escape, :HYPname))).nz))

```

Now we can use this replace the args of the quote block.

```julia
julia> e.args[3].args = [isa(param, Expr) ? fill_individual_param(param, :HYPname) : param for param in e2.args]
4-element Vector{Any}:
 :(#= REPL[13]:3 =#)
 :(aP::Array{Float64, 2} = fill(1.0, ($(Expr(:escape, :HYPname))).na, ($(Expr(:escape, :HYPname))).nz))
 :(#= REPL[13]:4 =#)
 :(cP::Array{Float64, 2} = fill(1.0, ($(Expr(:escape, :HYPname))).na, ($(Expr(:escape, :HYPname))).nz))

julia> e
:(struct HHsol
      #= REPL[13]:3 =#
      aP::Array{Float64, 2} = fill(1.0, ($(Expr(:escape, :HYPname))).na, ($(Expr(:escape, :HYPname))).nz)
      #= REPL[13]:4 =#
      cP::Array{Float64, 2} = fill(1.0, ($(Expr(:escape, :HYPname))).na, ($(Expr(:escape, :HYPname))).nz)
  end)

```

We can then turn that into a function:

```julia
julia> function fill_params(e, s, m)
            e.args[3].args = [isa(param, Expr) ? fill_individual_param(param, s) : param for param in e.args[3].args]
            return Parameters.with_kw(e, m, true)
       end
fill_params (generic function with 1 method)

julia> fill_params(
           :(struct HHsol
                  aP::Array{Float64,2}
                  cP::Array{Float64,2}
           end),
           :HYPname,
           @ __MODULE__
       )
quote
Base.@ __doc__ struct HHsol
            "Default: fill(1.0, HYPname.na, HYPname.nz)"
            aP::Array{Float64, 2}
            "Default: fill(1.0, HYPname.na, HYPname.nz)"
            cP::Array{Float64, 2}
            HHsol(; aP = fill(1.0, HYPname.na, HYPname.nz), cP = fill(1.0, HYPname.na, HYPname.nz)) = begin
                    #= C:\Users\kittisopikulm\.julia\packages\Parameters\MK0O4\src\Parameters.jl:493 =#
                    HHsol(aP, cP)
                end
            HHsol(aP, cP) = begin
                    #= C:\Users\kittisopikulm\.julia\packages\Parameters\MK0O4\src\Parameters.jl:505 =#
                    new(aP, cP)
                end
        end
    ()
    ()
    begin
        HHsol(pp::HHsol; kws...) = begin
                (Parameters).reconstruct(pp, kws)
            end
        HHsol(pp::HHsol, di::(Parameters).AbstractDict) = begin
                (Parameters).reconstruct(pp, di)
            end
        HHsol(pp::HHsol, di::Vararg{Tuple{Symbol, Any}}) = begin
                (Parameters).reconstruct(pp, di)
            end
    end
    function Base.show(io::IO, p::HHsol)
        if get(io, :compact, false) || get(io, :typeinfo, nothing) == HHsol
            Base.show_default(IOContext(io, :limit => true), p)
        else
            dump(IOContext(io, :limit => true), p, maxdepth = 1)
        end
    end
    macro unpack_HHsol(ex)
        esc((Parameters)._unpack(ex, Any[:aP, :cP]))
    end
    begin
        macro pack_HHsol()
            esc((Parameters)._pack_new(HHsol, Any[:aP, :cP]))
        end
    end
    HHsol
end

```

Now we can turn that function into a macro:

```julia
julia> macro fill_params(s, e)
           esc(fill_params(e, s, __module__ ))
       end
@fill_params (macro with 1 method)

julia> @macroexpand @fill_params(HYPname,struct HHsol
           aP::Array{Float64,2}
           cP::Array{Float64,2}
       end)
quote
    begin
        $(Expr(:meta, :doc))
        struct HHsol
            "Default: fill(1.0, HYPname.na, HYPname.nz)"
            aP::Array{Float64, 2}
            "Default: fill(1.0, HYPname.na, HYPname.nz)"
            cP::Array{Float64, 2}
            HHsol(; aP = fill(1.0, HYPname.na, HYPname.nz), cP = fill(1.0, HYPname.na, HYPname.nz)) = begin
                    HHsol(aP, cP)
                end
            HHsol(aP, cP) = begin
                    new(aP, cP)
                end
        end
    end
    ()
    ()
    begin
        HHsol(pp::HHsol; kws...) = begin
                (Parameters).reconstruct(pp, kws)
            end
        HHsol(pp::HHsol, di::(Parameters).AbstractDict) = begin
                (Parameters).reconstruct(pp, di)
            end
        HHsol(pp::HHsol, di::Vararg{Tuple{Symbol, Any}}) = begin
                (Parameters).reconstruct(pp, di)
            end
    end
    function Base.show(io::IO, p::HHsol)
        if get(io, :compact, false) || get(io, :typeinfo, nothing) == HHsol
            Base.show_default(IOContext(io, :limit => true), p)
        else
            dump(IOContext(io, :limit => true), p, maxdepth = 1)
        end
    end
    macro unpack_HHsol(ex)
        esc((Parameters)._unpack(ex, Any[:aP, :cP]))
    end
    begin
        macro pack_HHsol()
            esc((Parameters)._pack_new(HHsol, Any[:aP, :cP]))
        end
    end
    HHsol
end

```

We can then use it as follows.

````julia
julia> HYPname = (; na = 5, nz = 3)
(na = 5, nz = 3)

julia> @fill_params(HYPname,struct HHsol
           aP::Array{Float64,2}
           cP::Array{Float64,2}
       end)
HHsol

julia> HYPname = (; na = 5, nz = 3)
(na = 5, nz = 3)

julia> HHsol()
HHsol
  aP: Array{Float64}((5, 3)) [1.0 1.0 1.0; 1.0 1.0 1.0; … ; 1.0 1.0 1.0; 1.0 1.0 1.0]
  cP: Array{Float64}((5, 3)) [1.0 1.0 1.0; 1.0 1.0 1.0; … ; 1.0 1.0 1.0; 1.0 1.0 1.0]

julia> HYPname = (; na = 4, nz = 9)
(na = 4, nz = 9)

julia> HHsol()
HHsol
  aP: Array{Float64}((4, 9)) [1.0 1.0 … 1.0 1.0; 1.0 1.0 … 1.0 1.0; 1.0 1.0 … 1.0 1.0; 1.0 1.0 … 1.0 1.0]
  cP: Array{Float64}((4, 9)) [1.0 1.0 … 1.0 1.0; 1.0 1.0 … 1.0 1.0; 1.0 1.0 … 1.0 1.0; 1.0 1.0 … 1.0 1.0]```
````
