Use @eval within a function

I am new to metaprograming in Julia. The case is I have many vectors to initialize in a constructor. I came up with this code

function MyStruct(n::Int)
    vecs = [:x, :y, :z, :p]
    for v in vecs
        @eval $v = Vector{Float64}(undef, $n)
    end
    return @eval MyStruct($(vecs...))
end

Then I found that @eval is always evaluated in the module’s global scope. It is not a good idea to use @eval within a function. It can be performance killer. Also, @eval does not have scope to the local variable n, so I have to do interpolation, adding $ to every local variable in my function.

Any suggestions for the correct way of replacing repeated vector initialization within a constructor function?

Doesn’t seem to require macros. Try

function MyStruct(n::Int)
    vecs = [:x, :y, :z, :p]
    params = (Vector{Float64}(undef, n) for sym in vecs)
    return MyStruct(params...)
end
1 Like

Thank you! You are right. In this constructor case, it indeed doesn’t require macros. And seems like we don’t even need to define vecs if not for readability. A follow up question, in a another case, I want to assign vectors to a list of fields in a struct

mutable struct NewStruct
    x::Vector{Float64}
    y::Vector{Float64}
    z::Vector{Float64}
    p::Vector{Float64}
    NewStruct() = new()
end

function init(a::NewStruct)
    vecs = [:x, :y, :z, :p]
    for v in vecs
        @eval a.$v = zeros(10)
    end
end

Any idea how to use macro for this case?

You don’t need a macro or eval() in this case. You can just use the setproperty! function which already does what you want:


julia> function init(a::NewStruct)
           vecs = [:x, :y, :z, :p]
           for v in vecs
               setproperty!(a, v, zeros(10))
           end
       end
init (generic function with 1 method)

julia> init(NewStruct())
4 Likes

As others have pointed out, this can easily be done without any meta-programming and in general, metaprogramming is just the wrong tool for this job. However, if you’re interested in learning about metaprogramming, it is often useful to learn it with simple cases like this rather than with something complicated.

The tool you want for this is called a macro. I’d strongly recommend reading this section of the documentation: https://docs.julialang.org/en/v1/manual/metaprogramming/index.html. It’s very well written and useful.

3 Likes