Constructor functionality within Struct

Is this bad coding?

@with_kw struct X @deftype Float64

    a; b; c; d; e; f; g

    xv::Vector{Float64}

    yv = map(xv) do x
       # 10 lines of calculation using struct variables a - g.
    end

end

The do block could be replaced with an external function, it wouldn’t be used anywhere else and I wanted to avoid passing the half dozen variables to it.

Will the functionality of the do block be copied for every instance of the struct ?
Or just the result - yv (this would be preferable).

I personally always need a second more to understand do blocks than “normal” functions, but I think you have good reasons to do it like that – depending on how complex your actual struct is, this is the easiest to read for me, but I would also be curious about other ways to approach this.

But regarding your second question: With @macroexpand you can check the exact code that will be generated and see what will actually be stored in the struct:

expanded macro

(I removed everything after the struct definition and added some empty lines to make it more readable; also the calculation of ys is just a dummy of course)

@macroexpand @with_kw struct X @deftype Float64
           a; b; c; d; e; f; g
           xv::Vector{Float64}

           yv::Vector{Float64} = map(xv) do x
               x * a + b * c + d * e * f * g
           end
       end

    begin
        $(Expr(:meta, :doc))
        struct X
            a::Float64
            b::Float64
            c::Float64
            d::Float64
            e::Float64
            f::Float64
            g::Float64
            xv::Vector{Float64}
            "Default: map(xv) do x\n    #= REPL[24]:8 =#\n    x * a + b * c + d * e * f * g\nend"
            yv::Vector{Float64}


            X(; a = #= remaining fields, edited out =# , yv = map(xv) do x
                            #= REPL[24]:8 =#
                            x * a + b * c + d * e * f * g
                        end) = begin

                    X(a, b, c, d, e, f, g, xv, yv)
                end


            X(a, b, c, d, e, f, g, xv, yv) = begin
                    new(a, b, c, d, e, f, g, xv, yv)
                end
        end
    end

So the function to generate ys is “stored” just inside the constructor like X(; ..., ys = anonymous_fn(...)), but the struct just contains the plain values that come out of the computation. Note that I had to annotate ys::Vector{Float64} because of the @deftype Float64.

1 Like

Thank you. Nice explanation. and desired outcome :slight_smile:

1 Like