# How to copy the fields of a structure as new local variables?

**URL:** <https://discourse.julialang.org/t/how-to-copy-the-fields-of-a-structure-as-new-local-variables/125683>\
**Category:** General Usage\
**Created:** [February 8, 2025, 9:18am UTC](https://discourse.julialang.org/t/how-to-copy-the-fields-of-a-structure-as-new-local-variables/125683 "2025-02-08T09:18:02Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [February 8, 2025, 9:18am UTC](https://discourse.julialang.org/t/how-to-copy-the-fields-of-a-structure-as-new-local-variables/125683/1 "2025-02-08T09:18:02Z")

</div>

Let’s say I have a loooong `Parameters` structure and a function where I want to refer simply with the parameter names rather than something like `p.parameterx`, how can I “automatically” copy the struct fields as local parameters ?

This doesn’t work because of course `eval` happens at global scope:

```julia

@kwdef mutable struct Parameters
    a::Float64 = 0.1
    b::String = "hello"
end

function bar()
    p = Parameters()
    # create local variables a == 0.1 and b= "hello"
    fields = fieldnames(Parameters)
    for f in fields
        println(getproperty(p, f))
        eval(:(local $f = $(getproperty(p, f))))
    end
    println("$b $a !")
end

```

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [February 8, 2025, 9:26am UTC](https://discourse.julialang.org/t/how-to-copy-the-fields-of-a-structure-as-new-local-variables/125683/2 "2025-02-08T09:26:10Z")

</div>

hmm… it seems it’s not possible, the trick seems to eventually [eval the whole function and then call the function](https://stackoverflow.com/a/21268133/1586860), but the whole point it to make the code more readable also to people that doesn’t know Julia…

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [February 8, 2025, 10:09am UTC](https://discourse.julialang.org/t/how-to-copy-the-fields-of-a-structure-as-new-local-variables/125683/3 "2025-02-08T10:09:20Z")

</div>

Is [property destructuring](https://docs.julialang.org/en/v1/manual/functions/#Property-destructuring) an option?

```julia
@kwdef mutable struct Parameters
    a::Float64 = 0.1
    b::String = "hello"
end

function bar()
    p = Parameters()
    (; a, b) = p
    println("$b $a !")
end

```

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 8, 2025, 10:40am UTC](https://discourse.julialang.org/t/how-to-copy-the-fields-of-a-structure-as-new-local-variables/125683/4 "2025-02-08T10:40:07Z")

</div>

Provided the type definition was already evaluated and the type’s name is inlined, a macro call in the method body can automatically generate variables from the field names. An attempt:

```julia
macro fields2vars(t::Symbol, x)
    type = Core.eval( __module__ , t)
        if !isstructtype(type)
            throw(ArgumentError("@fields2vars only takes struct types, not $type."))
        end 
    esc(:( (; $(fieldnames(type)...)) = $x::$type ))
end

function bar2()
    p = Parameters()
    @fields2vars Parameters p
    println("$b $a !")
end

```

But since you’ll have to manually type the variables after the macro call to use them anyway, typing each used variable 1 more time doesn’t seem much more effort than this macro call, and the macro call constrains the code more because it needs a specific inlined type by definition-time to generate the local variables. In practice, you may not know the type even by compile-time, and property destructuring can be attempted at runtime.

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [February 8, 2025, 10:56am UTC](https://discourse.julialang.org/t/how-to-copy-the-fields-of-a-structure-as-new-local-variables/125683/5 "2025-02-08T10:56:18Z")

</div>

Thank you… it works in my user-case, where I have compiled struct with default values but want let users the option to override them:

```julia
@kwdef mutable struct Parameters
    a::Float64 = 0.1
    b::String = "hello"
end

macro fields2vars(t::Symbol, x)
    type = Core.eval( __module__ , t)
        if !isstructtype(type)
            throw(ArgumentError("@fieldvars only takes struct types, not $type."))
        end 
    esc(:( (; $(fieldnames(type)...)) = $x::$type ))
end

function bar2(;kwargs...)
    p = Parameters()
    # here keyword arguments are used to override the default values...
    for (kw,kwv) in kwargs
        found = false
        if kw in fieldnames(Parameters)
            setproperty!(p,kw,kwv)
            found = true
        end
        found || error("Keyword \"$kw\" is not a valid parameter.")
    end
    @fields2vars Parameters p
    println("$b $a !")
end

bar2()
bar2(a=0.2)

```

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [February 8, 2025, 11:07am UTC](https://discourse.julialang.org/t/how-to-copy-the-fields-of-a-structure-as-new-local-variables/125683/6 "2025-02-08T11:07:37Z")

</div>

You don’t need that mutating for-loop, `@kwdef` is designed to allow you to instantiate with compatible keyword arguments and input types, e.g. `p = Parameters(;kwargs...)`. The only practical difference is the custom error message for incompatible keywords being specific to `bar2` rather than the internal `Parameters`, and if you want to keep that, you can check `issubset(keys(kwargs), fieldnames(Parameters))` before you instantiate at all.
