Skip to content

deepcopy with non-trivial circular references fails in 1.11.2 #56775

Closed
@DrChainsaw

Description

Not sure if this is just a symptom of deepcopy not having much in terms of guaranteed behaviour, but it is no longer consistent with serialize => deserialize.

I tried to recreate it with a simpler structure (e.g. just Arrays which contain themselves) but couldn't. This is the most stripped down version I could create:

struct ProblemStruct{T}
    label::String # Just helps a bit when debugging
    inputs::T
end

using Serialization

let 
    problem = ProblemStruct("problem", ProblemStruct[])

    next = ProblemStruct("next", [problem])
    push!(problem.inputs, next) # Make a circular reference

    println("Original:")
    @show problem === next.inputs[1]
    @show problem.inputs[1] === next

    problemc, nextc = deepcopy((problem, next))
    println("\ndeepcopy:")
    @show problemc === nextc.inputs[1]
    @show problemc.inputs[1] === nextc

    println("\nserde:")
    problemds, nextds = let 
        io = PipeBuffer()
        serialize(io, (problem, next))
        deserialize(io)
    end
    @show problemds === nextds.inputs[1]
    @show problemds.inputs[1] === nextds

end;

Prints the following in Julia 1.11.2:

Original:
problem === next.inputs[1] = true    
problem.inputs[1] === next = true    

deepcopy:
problemc === nextc.inputs[1] = false 
problemc.inputs[1] === nextc = true  

serde:
problemds === nextds.inputs[1] = true
problemds.inputs[1] === nextds = true

And this in Julia 1.10.7:

Original:
problem === next.inputs[1] = true
problem.inputs[1] === next = true

deepcopy:
problemc === nextc.inputs[1] = true
problemc.inputs[1] === nextc = true

serde:
problemds === nextds.inputs[1] = true
problemds.inputs[1] === nextds = true

Fwiw: I can work around the problem on my side with the following:

function Base.deepcopy_internal(v::Vector{ProblemStruct}, stackdict::IdDict)
    v in keys(stackdict) && return stackdict[v]
    newv = similar(v)
    stackdict[v] = newv
    for (i, vi) in zip(eachindex(newv), v)
        newv[i] = Base.deepcopy_internal(vi, stackdict)
    end
    return newv
end

Versioninfo 1.11.2:

Julia Version 1.11.2
Commit 5e9a32e7af (2024-12-01 20:02 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: 12 × Intel(R) Core(TM) i7-5820K CPU @ 3.30GHz
  WORD_SIZE: 64
  LLVM: libLLVM-16.0.6 (ORCJIT, haswell)
Threads: 12 default, 0 interactive, 6 GC (on 12 virtual cores)
Environment:
  JULIA_DEPOT_PATH = E:/Programs/julia/.julia
  JULIA_PKG_DEVDIR = E:/Programs/julia/.julia/dev
  JULIA_EDITOR = code

Versioninfo 1.10.7:

Julia Version 1.10.7
Commit 4976d05258 (2024-11-26 15:57 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: 12 × Intel(R) Core(TM) i7-5820K CPU @ 3.30GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-15.0.7 (ORCJIT, haswell)
Threads: 1 default, 0 interactive, 1 GC (on 12 virtual cores)
Environment:
  JULIA_DEPOT_PATH = E:/Programs/julia/.julia
  JULIA_PKG_DEVDIR = E:/Programs/julia/.julia/dev

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugIndicates an unexpected problem or unintended behaviorregressionRegression in behavior compared to a previous versionregression 1.11Regression in the 1.11 releaseregression 1.12Regression in the 1.12 release

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions