# deep_copy

Definition: | object x = deep_copy(object x)
Description: | Create an independent clone of x, that does not rely on subsequent copy-on-write semantics. x: the object to clone.
pwa/p2js: | Introduced specifically for p2js, for more details see the Incompatibilities section of that documentation.
Comments: | Phix has pass by reference with copy on write semantics whereas JavaScript has pass by sharing semantics. Adding "with js" (equivalently javascript or javascript_semantics) to a source file effectively disables both in the desktop interpreter, and triggers appropriate run-time violations to indicate where deep_copy() is needed. Only in that way, and with thorough testing on the desktop, can we hope to ensure the transpiler does not generate pass-by-sharing-side-effect-laden JavaScript, which would need to be debugged using the browser development tools. Note that "with js" is ignored by the compiler, repl, and transpiler, and the latter errors out on "without js". Aside: I don’t really expect anyone to type out "with javascript_semantics" when they can just use "with js", however searching for the latter on rosettacode is [not] going to be very productive. TIP: set with debug/withjs=1 in pHeap.e to debug/OllyDbg a -c’d executable. Has no effect if x is an atom or string, since non-1 refcounts on those do not cause JavaScript (and/or p2js.js) any trouble. Since cloning something which has an attached delete_routine() is an almost sure-fire way to be left with a reference to reclaimed memory or a reclaimed slot in a table, this routine now [1.0.5+] throws an error should such be detected. Note that deep_copy does not produce thread-safe atoms and strings, it only does that for dword-sequences and even then not any string or atom elements they may contain.
Example: |
            O:={3}; P:=O;            O[1]:=5;   -- when transpiled to JavaScript: ARGH, P != {3} !!!
            O:={3}; P:=deep_copy(O); O[1]:=5;   -- when transpiled to JavaScript: ahhh, P == {3}
Of course that works as you would normally expect on desktop/Phix, with P=={3} in all cases and the caveat that the first line triggers a runtime violation on should there be a "with js" present. If you are thinking "extra typing!" when looking at that you would be correct, but if you’re also thinking "extra overhead!" then apart from the function call you’d be wrong, that kind of copy always used to have to quietly happen anyway, albeit a usually shallower copy, and fractionally later and the other way round, inside the O[1] assignment.
Implementation: | See builtins\repeat.e (an autoinclude) for details of the actual implementation. There is also a version in p2js.js which obviously uses native JavaScript functions not builtins\VM\pHeap.e\%:pAllocSeq, etc.
See Also: | repeat, Incompatibilities
Technicalia | Sometimes you may need to perform a deep analysis of what your refcounts really are. Below are a couple of routines I quickly cobbled together to do just that, preserved for posterity. Note that I was analysing a static/file-level variable, if you are passing in an object to get the refcount(s) for, you’ll obviously have to adjust by -1. Every case will need its own set of tweaks, and (hopefully) will/may lead to a permanent fix so that it is never needed again, which is why this is not (worth making into) any kind of builtin. Fairly obviously this sort of stuff should never ever be thrown at pwa/p2js.
    sequence dll    -- (doubly linked list that was giving me jip)

    function get_dll_refcount()
        -- get the refcount for dll
        integer refcount
        #ilASM{
            [32]
                mov eax,[dll]
                mov eax,[ebx+eax*4-8]
                mov [refcount],eax
            [64]
                mov rax,[dll]
                mov rax,[rbx+rax*4-16]
                mov [refcount],rax
            []
              }
        return refcount
    end function

    function get_dll_refcounts()
        -- get the refcount for all top-level elements of dll [which were all sequences in my case]
        integer l = length(dll)
        sequence refcounts = repeat(0,l)
        for i=1 to l do
            sequence dlli = dll[i]
            dll[i] = 0
            integer refcount
            #ilASM{
                [32]
                    mov eax,[dlli]
                    mov eax,[ebx+eax*4-8]
                    mov [refcount],eax
                [64]
                    mov rax,[dlli]
                    mov rax,[rbx+rax*4-16]
                    mov [refcount],rax
                []
                  }
            dll[i] = dlli
            dlli = {}
            refcounts[i] = refcount
        end for
        return refcounts
    end function