# Is there a way to deepcopy a module?

**URL:** <https://discourse.julialang.org/t/is-there-a-way-to-deepcopy-a-module/84094>\
**Category:** General Usage\
**Tags:** package\
**Created:** [July 12, 2022, 9:08am UTC](https://discourse.julialang.org/t/is-there-a-way-to-deepcopy-a-module/84094 "2022-07-12T09:08:19Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![danielw2904](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielw2904/32/10890_2.png) [@danielw2904](https://discourse.julialang.org/u/danielw2904)\
**Post date:** [July 12, 2022, 9:08am UTC](https://discourse.julialang.org/t/is-there-a-way-to-deepcopy-a-module/84094/1 "2022-07-12T09:08:19Z")

</div>

```julia
using DeepcopyModules
module M; x = 1; f() = (global x += 1); end
M2 = deepcopy_module(M)

```

The [package is on github](https://github.com/NHDaly/DeepcopyModules.jl). However, this code crashes. Is there any other way?

The error is:

```julia
main at /buildworker/worker/package_linux64/build/cli/loader_exe.c:42unknown function (ip: 0x7efc98030d8f)__libc_start_main at /lib/x86_64-linux-gnu/libc.so.6 (unknown line)Process julia aborted (core dumped) at Mon Jul 11 10:36:15 2022

```

X-post from [here](https://www.reddit.com/r/Julia/comments/vwdlh7/is_there_a_way_to_deepcopy_a_module/)

---

<div class="post-metadata">

**Author:** ![danielw2904](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielw2904/32/10890_2.png) [@danielw2904](https://discourse.julialang.org/u/danielw2904)\
**Post date:** [July 20, 2022, 3:08pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-deepcopy-a-module/84094/2 "2022-07-20T15:08:36Z")

</div>

I almost managed to deepcopy a module without going into the C internals. The only link that remains is that a change of a function definition in the initial module affects the copy. Any ideas how to get rid of that?

```julia
function getmodulename(x::Module)
    ## extracts name of passed module
    nn = quote
        $x
    end
    n_with_parent = nn.args[2] |> string
    ## Works for nested modules
    parent = parentmodule(x)
    m_maybe = match(Regex("(?<=$(parent)\\.).*"), n_with_parent)
    return Symbol(m_maybe.match)
end

function copy_module(m::Module, new::Module)
    mname = getmodulename(m)
    unused_names = [mname, Symbol("#eval"), Symbol("#include"), :eval, :include]
    mnames = names(m; all = true)
    filter!(x-> x ∉ unused_names && !startswith(string(x), '#'), mnames)
    properties = [getproperty(m, n) for n in mnames]
    ismodule = isa.(properties, Ref(Module)) 
    ## Modules get copied recursively
    modules = properties[ismodule]
    for _m in modules
        _mname = getmodulename(_m)
        _new = new.Core.eval(new, :(module $_mname end))
        copy_module(_m, _new)
    end
    ## Functions cannot be copied but are defined such that
    ## a change in `new` does not affect `m`
    ## without a change in `new` the function will refer to
    ## whatever is currently in `m` (incl. changes)
    isfunction = isa.(properties, Ref(Function))
    functions = properties[isfunction]
    for (_n, _f) in zip(mnames[isfunction], functions)
        new.Core.eval(new, :($(_n)(x) = (y->$(_f)(y))(x)))
    end
    ## Values are assigned with deepcopy
    assignments = [:($nn = deepcopy($pp)) for (nn,pp) in zip(mnames[.!(ismodule) .&& .!(isfunction)], properties[.!(ismodule).&& .!(isfunction)])]
    [new.Core.eval(new, i) for i in assignments]
    return new
end

module A 
x = 1
y = [1,3,4]
f(x) = println(x)
module C
z = [1,2,3]
end
end

module B end
copy_module(A, B)

A.f("HI")
B.f("HI")
A.f(x) = x^2 # modifies A.f AND B.f
A.f("HI")
B.f("HI")

B.f(x) = lowercase(x) # modifies ONLY B.f
A.f("HI")
B.f("HI")

A.x
B.x
A.Core.eval(A, :(x = 2)) # modifies ONLY A.x
A.x
B.x

B.Core.eval(B, :(x = "HI")) # modifies ONLY B.x
A.x
B.x

B.C.z .= [4,5,6] # modifies ONLY B.C.z
A.C.z
B.C.z

A.y !== B.y ## not same memory
A.C.z !== B.C.z ## not same memory

```
