# Behaviors of \`deepcopy\` for a function constructed with different ways of referencing a global variable

**URL:** <https://discourse.julialang.org/t/behaviors-of-deepcopy-for-a-function-constructed-with-different-ways-of-referencing-a-global-variable/128939>\
**Category:** General Usage\
**Tags:** function, closure\
**Created:** [May 13, 2025, 12:23am UTC](https://discourse.julialang.org/t/behaviors-of-deepcopy-for-a-function-constructed-with-different-ways-of-referencing-a-global-variable/128939 "2025-05-13T00:23:01Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![frankwswang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/frankwswang/32/18561_2.png) [@frankwswang](https://discourse.julialang.org/u/frankwswang)\
**Post date:** [May 13, 2025, 12:23am UTC](https://discourse.julialang.org/t/behaviors-of-deepcopy-for-a-function-constructed-with-different-ways-of-referencing-a-global-variable/128939/1 "2025-05-13T00:23:01Z")

</div>

This discovery stemmed from the [reply](https://discourse.julialang.org/t/is-it-possible-to-know-if-a-function-has-captured-variables/128934/8) in another post, but since it’s less relevant to the initial post, I thought I would make a new post dedicated to it.

```julia
julia> box = fill(1)
0-dimensional Array{Int64, 0}:
1

julia> function f1()
           function (x)
               box[] + 1
           end
       end
f1 (generic function with 1 method)

julia> function f2(localBox::Array{Int, 0})
           function (x)
               localBox[] + 1
           end
       end
f2 (generic function with 1 method)

julia> f1c = f1()
#1 (generic function with 1 method)

julia> f2c = f2(box)
#3 (generic function with 1 method)

julia> box[] += 1
2

julia> f1c(1)
3

julia> f2c(1)
3

julia> f1c_dc = deepcopy(f1c)
#1 (generic function with 1 method)

julia> f2c_dc = deepcopy(f2c)
#3 (generic function with 1 method)

julia> box[] += 1
3

julia> f2c_dc(1)
3

julia> f1c_dc(1)
4

julia> check_type(::F) where {F} = (isbitstype(F), Base.issingletontype(F))
check_type (generic function with 1 method)

julia> check_type(f2c)
(false, false)

julia> check_type(f1c)
(true, true)

```

Why didn’t `deepcopy` sever the reference to the global variable `box` for `f1c_dc`? And why is `f1c` considered an instance of `bitstype` and `singletontype` even though it technically references the “same” global variable `box` as `f2c`? I understand that for `f2c`, the `box` was never directly used to construct its body, but through a local variable `localBox` that points to `box`. However, the result remains effectively the same for `f1c` and `f2c`, as they both reference the same data stored in `box`.

Consider the case where an object is not a closure but a `Tuple`:

```julia
julia> v1 = (box,)
(fill(3),)

julia> v2 = deepcopy(v1)
(fill(3),)

julia> box[] = 5
5

julia> v1
(fill(5),)

julia> v2
(fill(3),)

```

Even though `v1` is constructed by directly using `box`, applying `deepcopy` on `v1` sever its internal data’s connection to `box` (see `v2`). Why does `deepcopy` not affect `f1c` the same way it affects `f2c`?

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [May 13, 2025, 12:31am UTC](https://discourse.julialang.org/t/behaviors-of-deepcopy-for-a-function-constructed-with-different-ways-of-referencing-a-global-variable/128939/2 "2025-05-13T00:31:56Z")

</div>

> [@frankwswang](#):
>
> And why is `f1c` considered an instance of `bitstype` and `singletontype` even though it technically references the “same” global variable `box` as `f2c`?

Flip the question on its head, why can’t the closure `f2c` have a singleton type? Hint: methods of closures are NOT redefined when the outer function is called.

---

<div class="post-metadata">

**Author:** ![frankwswang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/frankwswang/32/18561_2.png) [@frankwswang](https://discourse.julialang.org/u/frankwswang)\
**Post date:** [May 13, 2025, 1:30am UTC](https://discourse.julialang.org/t/behaviors-of-deepcopy-for-a-function-constructed-with-different-ways-of-referencing-a-global-variable/128939/3 "2025-05-13T01:30:07Z")

</div>

Thanks for the hint!! It seems like the way I thought of `Function`, as `struct` with attributes (fields) and methods, is no longer applicable in this case. Here’s what I understand now:

For `f1`, `box` was not an assigned field of the closure it returns, but simply a variable directly inside the definition (function body) of the closure, except it’s declared outside the closure scope. So, as soon as `f1` is defined, even before it is called, it is certain that there can only be one instance of the closure (which technically should not even be considered a “closure” based on your and [@danielwe](https://discourse.julialang.org/u/danielwe) 's comments ([1](https://discourse.julialang.org/t/is-it-possible-to-know-if-a-function-has-captured-variables/128934/9), [2](https://discourse.julialang.org/t/is-it-possible-to-know-if-a-function-has-captured-variables/128934/10)) on the other post) that `f1` generates. Thus, `typeof(f1c)` is deemed a singleton type. And because `typeof(f1c)` is a singleton, it should have one and only one instance (characterized by its type information), which is `f1c`. So `deepcopy` cannot just create another instance that is not identical to `f1c`. Therefore, `deepcopy` cannot sever the `f1c`’s reference to the global variable `box` either.

However, for `f2`, there can be many instances of the closure it generates, depending on the specific value of `localBbox` passed in. So `f2` in fact behaves like a struct with a single field (store the value of `localBbox` for each instance) and a corresponding method that uses the field. Hence, `f2c` is not an instance of a singleton type. Correspondingly, `deepcopy` also copies the data stored inside it.

Hopefully, what I described above is a more accurate mind model of how closures and functions with out-of-scope variables generally work. Thanks!!
