How to copy all fields without changing the referece?


#1

Hi guys!

I have a type with many fields and I need to define the function copy!(A,B). My question is: is there any way to copy all the fields automatically? Something like deepcopy but without changing the reference?

As of now, I am doing it manually:

function copy!(A::MyType, B::MyType) = begin
    A.f1 = B.f1
    A.f2 = B.f2

    copy!(A.v1, B.v1)
    ...
end

#2

Maybe use fieldnames to iterate over all fields, which you get and set with getfield and setfield!.


#3

Looping over fieldnames with getfield and setfield! is not type-stable so it’s slower. I agree that it would be nice to have a generic version of this.

It can probably be made using a generated function.


#4

If you’re worried about speed, you could create the copy! function with a macro at type creation.


#5

If you’re worried about speed, you could create the copy! function with a macro at type creation.

I needed something similar, so generated copy! function with following.
You might be able to model something for you use case.


function CompositeCopy!(T::Symbol)
    dataType = eval(current_module(), T)
    fieldNames = fieldnames(dataType)
    fieldTypes = dataType.types
    expressions = Array(Expr, numFields)

    for i = 1 : length(fieldNames)
        fieldName = fieldNames[i]
        fieldType = fieldTypes[i]
        @assert fieldType.mutable == method_exists(copy!, (fieldType, fieldType))

        if method_exists(copy!, (fieldType, fieldType))
            expressions[i] = :(copy!(x.$fieldName, y.$fieldName))
        else
            expressions[i] = :(x.$fieldName = y.$fieldName)
        end
    end

    body = Expr(:block, expressions...)

    quote
        function Base.copy!(x::$T, y::$T)
            $body
            return x
        end
    end
end


#6

Why don’t you make your example into a @generated function? This is what they are for.


#7

Yes, I probably should make this a generated function.

I think I coded this in v0.3 before generated functions.
And then I vaguely remember a push limit use of generated functions. Perhaps something to do precompilation?
Are there any drawbacks to generated functions?


#8

Hi guys!

Thanks for the answers. I will try to adapt your code @greg_plowman for my needs, Thanks!


#9

They require the Julia runtime so you cannot statically compile code which has them I think. Other than that? I don’t think so?