# How is \`deepcopy\` so clever regarding aliasing and self-reference?

**URL:** https://discourse.julialang.org/t/how-is-deepcopy-so-clever-regarding-aliasing-and-self-reference/113235
**Category:** General Usage
**Tags:** self-reference, deepcopy, serialization, ref
**Created:** [April 19, 2024, 12:44pm UTC](https://discourse.julialang.org/t/how-is-deepcopy-so-clever-regarding-aliasing-and-self-reference/113235 "2024-04-19T12:44:02Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![iago-lito](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/iago-lito/32/31924_2.png) [@iago-lito](https://discourse.julialang.org/u/iago-lito)
#### Post date: [April 19, 2024, 12:44pm UTC](https://discourse.julialang.org/t/how-is-deepcopy-so-clever-regarding-aliasing-and-self-reference/113235/1 "2024-04-19T12:44:02Z")

</div>

I find this behaviour _very fortunate_, but also _black magic_:

```julia
a = [5]
u = [a, a, a]
v = deepcopy(u)
v[1][1] = 8
v # [[8], [8], [8]] # My naive 'deepcopy' would have produced [[8], [5], [5]] instead.

```

I expected `deepcopy` to be naive and produce three independent copies of `a` within `v` . But it seems _much smarter_ and somehow figures that all three values in `u` are aliases of each other and then it reproduces the same aliasing relations within `v` . This is very fortunate, but how does it do so?

The [doc](https://docs.julialang.org/en/v1/base/base/#Base.deepcopy) says:

> Calling `deepcopy` on an object should generally have the same effect as serializing and then deserializing it.

But again, my naive `u -> serialize -> file -> deserialize -> v` roundtrip would have produced three independent values within `v`, and the result would have been `[[8], [5], [5]]` again.

Is it specified which kind of “serialization” is clever enough for specifying `deepcopy`?

---

<div class="post-metadata">

### Author: ![Tortar](https://avatars.discourse-cdn.com/v4/letter/t/6bbea6/32.png) [@Tortar](https://discourse.julialang.org/u/Tortar)
#### Post date: [April 19, 2024, 1:01pm UTC](https://discourse.julialang.org/t/how-is-deepcopy-so-clever-regarding-aliasing-and-self-reference/113235/2 "2024-04-19T13:01:27Z")

</div>

I looked at it sometime ago, if I remember correctly the object is explored in a recursive fashion and an IdDict is used to keep track of which objects have already been seen so that to be able to preserve object identities.

Indeed I learnt it by incorrectly assuming that it worked as you thought as well 😃 : see [Possible performance improvements for `deepcopy`?](https://discourse.julialang.org/t/possible-performance-improvements-for-deepcopy/107719)

---

<div class="post-metadata">

### Author: ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)
#### Post date: [April 19, 2024, 1:07pm UTC](https://discourse.julialang.org/t/how-is-deepcopy-so-clever-regarding-aliasing-and-self-reference/113235/3 "2024-04-19T13:07:48Z")

</div>

This IdDict trick is also how Functors.jl works, to handle elements appearing more than once. For your serialisation, you could consider doing something like this, to keep only one copy of `a` before proceeding:

```julia
julia> a = [5];

julia> u = [a, a, a];

julia> fmapstructure(identity, u, prune=nothing)
3-element Vector{Union{Nothing, Vector{Int64}}}:
 [5]
 nothing
 nothing

```

---

<div class="post-metadata">

### Author: ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)
#### Post date: [April 19, 2024, 1:29pm UTC](https://discourse.julialang.org/t/how-is-deepcopy-so-clever-regarding-aliasing-and-self-reference/113235/4 "2024-04-19T13:29:35Z")

</div>

> [@iago-lito](#):
>
> Is it specified which kind of “serialization” is clever enough for specifying `deepcopy`?

`Serialization.serialize` is! It’s worth noting this is how Julia communicates between workers, so it’s quite valuable to have this behavior.

```Julia
julia> a = [5];

julia> u = [a, a, a];

julia> using Serialization

julia> serialize("test.jls", u)

julia> v = deserialize("test.jls")
3-element Vector{Vector{Int64}}:
 [5]
 [5]
 [5]

julia> v[1][1]=8
8

julia> v
3-element Vector{Vector{Int64}}:
 [8]
 [8]
 [8]

```

---

<div class="post-metadata">

### Author: ![iago-lito](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/iago-lito/32/31924_2.png) [@iago-lito](https://discourse.julialang.org/u/iago-lito)
#### Post date: [April 19, 2024, 1:43pm UTC](https://discourse.julialang.org/t/how-is-deepcopy-so-clever-regarding-aliasing-and-self-reference/113235/5 "2024-04-19T13:43:10Z")

</div>

Thank you @Tortar @mcabbott @mbauman!

IIUC some underlying data model like the following is what makes both `deepcopy` and `serialize` clever:

```julia
u:
  sub_values: (≈ "IdDict")
     <1>: 5
     <2>: [<1>]
  type: Vector{...}
  value: [<2>, <2>, <2>]

```

Black magic is gone, and only bliss remains ^ ^
