# Generic implementation of Base.copy method for custom Types (using iternation over fieldnames?)

**URL:** <https://discourse.julialang.org/t/generic-implementation-of-base-copy-method-for-custom-types-using-iternation-over-fieldnames/130696>\
**Category:** General Usage\
**Created:** [July 14, 2025, 10:29am UTC](https://discourse.julialang.org/t/generic-implementation-of-base-copy-method-for-custom-types-using-iternation-over-fieldnames/130696 "2025-07-14T10:29:55Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![pierre-haessig](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pierre-haessig/32/217129_2.png) [@pierre-haessig](https://discourse.julialang.org/u/pierre-haessig)\
**Post date:** [July 14, 2025, 10:29am UTC](https://discourse.julialang.org/t/generic-implementation-of-base-copy-method-for-custom-types-using-iternation-over-fieldnames/130696/1 "2025-07-14T10:29:55Z")

</div>

Hello,

This question has probably been answered several times, but oddly enough this morning I can’t get the proper answer.

Context: I have a code base with several _mutable_ custom parametric types (i.e. structures which in the application context I call “components”), each having quite many fields (actual code base is [Microgrids.jl/src/components.jl at main · Microgrids-X/Microgrids.jl · GitHub](https://github.com/Microgrids-X/Microgrids.jl/blob/main/src/components.jl)):

```julia
mutable struct CompA
    p1::Float64
    #...
    pn::Float64
end
# CompB, CompC...
mutable struct CompZ
    p1::Float64
    #...
    pn::Float64
end

```

Then on one morning I realize I may need an implementation of the [`Base.copy`](https://docs.julialang.org/en/v1/base/base/#Base.copy) method. For one component, I write it manually, but then I realize I may need to do it for all of them…

I found a discussion about iterating over `fieldnames` in [How to copy all fields without changing the referece?](https://discourse.julialang.org/t/how-to-copy-all-fields-without-changing-the-referece/945), where a warning is given about a performance impact (and I’m not impacted by performance issue for my potential usage of copy). But oddly enough, I didn’t find a generic recipe to avoid manually typing each field name.

Here is a recipe I ended up with:

```julia
function Base.copy(c::CompA)
    T = typeof(c)
    args = (getfield(c, name) for name in fieldnames(T))
    return T(args...)
end

```

I can duplicate this definition for each component for which I need `copy`. Also, I think that this `copy` definition is generic enough so that if some types inherit from one common super type, I just need to define it for the supertype, correct?

I’ll be glad to get feedback on the topic, or simply links to relevant previous discussions. I also had in mind there existed a package with macros specifically meant for this use case.

---

<div class="post-metadata">

**Author:** ![pierre-haessig](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pierre-haessig/32/217129_2.png) [@pierre-haessig](https://discourse.julialang.org/u/pierre-haessig)\
**Post date:** [July 14, 2025, 10:35am UTC](https://discourse.julialang.org/t/generic-implementation-of-base-copy-method-for-custom-types-using-iternation-over-fieldnames/130696/2 "2025-07-14T10:35:52Z")

</div>

> [@pierre-haessig](#):
>
> Also, I think that this `copy` definition is generic enough so that if some types inherit from one common super type, I just need to define it for the supertype, correct?

I was too optimistic about the handling of sibling types. I believe the correct way to handle all the inherited types of some `SuperComp` supertype is instead:

```julia
function Base.copy(c::Comp) where {Comp <: SuperComp}
    T = typeof(c)
    args = (getfield(c, name) for name in fieldnames(T))
    return T(args...)
end

```

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [July 14, 2025, 10:59am UTC](https://discourse.julialang.org/t/generic-implementation-of-base-copy-method-for-custom-types-using-iternation-over-fieldnames/130696/3 "2025-07-14T10:59:50Z")

</div>

This should be both generic and performant:

```julia
using ConstructionBase

Base.copy(x::YourType) = constructorof(typeof(x))(getfields(x)...)

```

---

<div class="post-metadata">

**Author:** ![pierre-haessig](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pierre-haessig/32/217129_2.png) [@pierre-haessig](https://discourse.julialang.org/u/pierre-haessig)\
**Post date:** [July 14, 2025, 12:55pm UTC](https://discourse.julialang.org/t/generic-implementation-of-base-copy-method-for-custom-types-using-iternation-over-fieldnames/130696/4 "2025-07-14T12:55:11Z")

</div>

Thanks a lot for the reference to [GitHub - JuliaObjects/ConstructionBase.jl: Primitives for construction of objects](https://github.com/JuliaObjects/ConstructionBase.jl) which I didn’t know.

In the end, I’ll probably trade performance against not adding an extra dependency, but it’s still interesting to see how the specific methods were implemented:

- [`constructorof`](https://github.com/JuliaObjects/ConstructionBase.jl/blob/51da6157bc705212b39f29ad5e7c66168015fba5/src/ConstructionBase.jl#L29) (+ also in [functions.jl](https://github.com/JuliaObjects/ConstructionBase.jl/blob/51da6157bc705212b39f29ad5e7c66168015fba5/src/functions.jl#L21), but only for function types?)
- [`getfields(obj::T) where {T}`](https://github.com/JuliaObjects/ConstructionBase.jl/blob/51da6157bc705212b39f29ad5e7c66168015fba5/src/ConstructionBase.jl#L80)

So I see that for the constructor, the “secret sauce” is to return `Base.typename(T).wrapper` rather than `T` itself. I didn’t know this syntax, and I have no idea why it may be more performant.

For `getfields`, I understand that the key point is to construct a type-specific `NamedTuple` to host the arguments which looks pretty neat.
