# Meaning of copy for arrays

**URL:** <https://discourse.julialang.org/t/meaning-of-copy-for-arrays/43420>\
**Category:** Internals & Design\
**Created:** [July 21, 2020, 8:36am UTC](https://discourse.julialang.org/t/meaning-of-copy-for-arrays/43420 "2020-07-21T08:36:23Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![dlfivefifty](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlfivefifty/32/1959_2.png) [@dlfivefifty](https://discourse.julialang.org/u/dlfivefifty)\
**Post date:** [July 21, 2020, 8:36am UTC](https://discourse.julialang.org/t/meaning-of-copy-for-arrays/43420/1 "2020-07-21T08:36:23Z")

</div>

Is there a clear description of what “contract” `copy(::AbstractArray)` should implement? The docs are not very precise. We have the following examples:

```julia
julia> copy(1:6) # just returns the same immutable type
1:6

julia> copy([1,2]) # makes a copy in memory
2-element Array{Int64,1}:
 1
 2

julia> copy([1,2]') # makes a copy in memory as an Adjoint
1×2 Adjoint{Int64,Array{Int64,1}}:
 1 2

julia> copy([1 2; 3 4]') # makes a copy in memory as a Matrix
2×2 Array{Int64,2}:
 1 3
 2 4
julia> copy((1:2)') # makes a copy in memory as an Adjoint
1×2 Adjoint{Int64,Array{Int64,1}}:
 1 2

```

I would guess there’s the following contract:

1. If array `A` is immutable (`setindex!` errors) then `C = copy(A)` need only satisfy `C == A`.
2. If array `A` is mutable (`setindex!` changes the entries), then `C = copy(A)` needs to satisfy `C == A`, `C` must be mutable, changing `C` does not change any entry of `A`.

We also have the requirement `C'b == A'b` and `transpose(C)*b == transpose(A)*b` for a vector `b`, which is why the adjoints of vectors need to return an adjoint, even though adjoints of matrices do not.

If my interpretation of the contract is correct, then the last example could have returned an immutable `Adjoint(1:2)`.

Is this a correct interpretation? I could make a PR to the doc string for `copy` if it is.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 21, 2020, 9:53am UTC](https://discourse.julialang.org/t/meaning-of-copy-for-arrays/43420/2 "2020-07-21T09:53:44Z")

</div>

I often wondered about this too.

Also, note that “mutability” is not something that callers can inspect, and it _may not be uniform for the whole array_ — `setindex!` can error for some indices, and work for some others. This is not only a theoretical concern, cf the various packages which provide a “concatenating view”.

I would propose the following contract: if `b = copy(a)`, then no operation on `b` can change the contents of `a`, ie if `c = collect(a)` then `c == a` will continue to hold no matter what is done to `b`.

---

<div class="post-metadata">

**Author:** ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)\
**Post date:** [July 21, 2020, 9:59am UTC](https://discourse.julialang.org/t/meaning-of-copy-for-arrays/43420/3 "2020-07-21T09:59:32Z")

</div>

> [@Tamas\_Papp](#):
>
> if `b = copy(a)` , then no operation on `b` can change the contents of `a`

Doesn’t this hold only for `deepcopy`?

---

<div class="post-metadata">

**Author:** ![dlfivefifty](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlfivefifty/32/1959_2.png) [@dlfivefifty](https://discourse.julialang.org/u/dlfivefifty)\
**Post date:** [July 21, 2020, 10:01am UTC](https://discourse.julialang.org/t/meaning-of-copy-for-arrays/43420/4 "2020-07-21T10:01:39Z")

</div>

The difference between `copy` and `deepcopy` is only articulated for types, not for arrays. Unfortunately `copy` has two different meanings, as seen in the example where the `copy` of an `Adjoint` returns a `Matrix`.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 21, 2020, 10:19am UTC](https://discourse.julialang.org/t/meaning-of-copy-for-arrays/43420/5 "2020-07-21T10:19:42Z")

</div>

Thanks, I should clarify: the invariance is for first-level array ops like `setindex!`, `push!`, `pop!`.

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [July 21, 2020, 1:19pm UTC](https://discourse.julialang.org/t/meaning-of-copy-for-arrays/43420/6 "2020-07-21T13:19:13Z")

</div>

I think no operation on `b` itself can change `a` itself, operations over their elements change the element, and the element may be present in more than one struct/array.

To me seems natural that `copy` is just the shallow version of `deepcopy`. This is, changes to things that are clearly stored in the outermost object, and not inside some inner object, do not affect the copy, however changing an inner object can affect the copy (as they both simply happen to share it).  
Consequently, if you replace the value in a field or position, the copy is not affected; if you delete elements (a property of the outermost object, clearly), the copy is not affected; if you change a field of an element of the original array, well, the same element is stored in the copy, and so the change will be reflected, but it is not like the copy itself has changed.

---

<div class="post-metadata">

**Author:** ![dlfivefifty](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlfivefifty/32/1959_2.png) [@dlfivefifty](https://discourse.julialang.org/u/dlfivefifty)\
**Post date:** [July 21, 2020, 1:23pm UTC](https://discourse.julialang.org/t/meaning-of-copy-for-arrays/43420/7 "2020-07-21T13:23:09Z")

</div>

I think talking about fields in terms of a definition of `copy` does not fit here, where the return type can be something completely different (with completely different fields)

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [July 21, 2020, 1:31pm UTC](https://discourse.julialang.org/t/meaning-of-copy-for-arrays/43420/8 "2020-07-21T13:31:49Z")

</div>

In which case are you thinking exactly? The `copy` may be a different type, that internally has different fields, however the copy often have the same public API than the original. The fields can be seen in a less technical light and a more semantic one, this is, as the properties/information of the object itself (but not inner objects) are copied (even if the exact internal struct fields are not the same).

---

<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:** [July 21, 2020, 2:36pm UTC](https://discourse.julialang.org/t/meaning-of-copy-for-arrays/43420/9 "2020-07-21T14:36:04Z")

</div>

> [@dlfivefifty](#):
>
> Is this a correct interpretation? I could make a PR to the doc string for `copy` if it is.

Yes, you’ve identified exactly the crux of the issue. Another good motivating example is `view`s; we now have `copy(view(A, I...))` defined to be `A[I...]` by default. In fact, I think it makes sense to try to align indexing and `copy`.

---

<div class="post-metadata">

**Author:** ![johnmyleswhite](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johnmyleswhite/32/31_2.png) [@johnmyleswhite](https://discourse.julialang.org/u/johnmyleswhite)\
**Post date:** [July 21, 2020, 3:01pm UTC](https://discourse.julialang.org/t/meaning-of-copy-for-arrays/43420/10 "2020-07-21T15:01:58Z")

</div>

FWIW, having come back to Julia after a pause, I was surprised that copying a DataFrame seems to be a deep copy. I’d love to see the Julia community standardize the meaning of these generic functions and do more to help libraries coordinate around a consistent set of guarantees.

---

<div class="post-metadata">

**Author:** ![dlfivefifty](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlfivefifty/32/1959_2.png) [@dlfivefifty](https://discourse.julialang.org/u/dlfivefifty)\
**Post date:** [July 21, 2020, 3:28pm UTC](https://discourse.julialang.org/t/meaning-of-copy-for-arrays/43420/11 "2020-07-21T15:28:12Z")

</div>

> [@Tamas\_Papp](#):
>
> I would propose the following contract: if `b = copy(a)` , then no operation on `b` can change the contents of `a`

Just to be clear it should only be “one level”, that is:

```julia
julia> A = [[1,2]]
1-element Array{Array{Int64,1},1}:
 [1, 2]

julia> copy(A)[1][1] = 4
4

julia> A
1-element Array{Array{Int64,1},1}:
 [4, 2]

```

So I think the entries of an array play the same role w.r.t. `copy` as fields do for other types.

---

<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:** [July 21, 2020, 5:15pm UTC](https://discourse.julialang.org/t/meaning-of-copy-for-arrays/43420/12 "2020-07-21T17:15:45Z")

</div>

The challenge in Julia is that it’s not always entirely clear what “one level” means. DataFrames is a great example. Is it a vector of vectors? Or a matrix of elements? Both? In fact, DataFrames `copy` is never a `deepcopy`, but you can see this tension (and the connection to indexing!) directly in the source:

[https://github.com/JuliaData/DataFrames.jl/blob/ddba103ca71e73fa258cd1ea833e0240b3dabc11/src/dataframe/dataframe.jl#L822-L836](https://github.com/JuliaData/DataFrames.jl/blob/ddba103ca71e73fa258cd1ea833e0240b3dabc11/src/dataframe/dataframe.jl#L822-L836)
