Copy Semantics - r3n/rebol-wiki GitHub Wiki
This is a preliminary document to specify the semantics of COPY for A80. This also applies to MAKE object! which preforms a COPY as a default action.
When a copy of a block or object is made, the copy operation handles various datatypes differently:
- immediate values - these are always copied (integer! decimal! logic! etc.)
- indirect values - can be copied if so desired (string! binary! block! etc.)
- restricted values - cannot be copied (gob!, task!, port!)
There are a few useful modes of copying:
- shallow - copy a block or object keeping all its values as non-copied references (values are shared).
- deep - copy a block or object, then copy all its series values (values are not shared).
- all - same as deep, but also copy all other copyable values such as bitsets, vectors, images, maps, objects, errors, etc.
- bind - same as deep, but also copy functions and closures that will be rebound in a new environment (this is a special mode used by MAKE object!)
- COPY/types - specify as a typeset the values to be copied. Note that you can use /types without /deep, in which case the copy is applied only to the top level of values.
- COPY/deep - perform the copy recursively on each value. If you use /deep without /types, it is assumed that you want to copy all series values (any-string!, binary!, and any-block!) but not bitsets, images, vectors, maps, functions, or objects.
Here is a table of types copied by default on COPY/deep and MAKE object!:
<TR> <TD BGCOLOR="#99CCFF"><B>Datatype</b></td> <TD BGCOLOR="#99CCFF"><B>COPY and MAKE</b></td> </tr> <TR> <TD><B>strings</b></td> <TD>yes</td> </tr> <TR> <TD><B>binary</b></td> <TD>yes</td> </tr> <TR> <TD><B>bitsets</b></td> <TD>no</td> </tr> <TR> <TD><B>vectors</b></td> <TD>no</td> </tr> <TR> <TD><B>images</b></td> <TD>no</td> </tr> <TR> <TD><B>gobs</b></td> <TD>no</td> </tr> <TR> <TD><B>blocks</b></td> <TD>yes</td> </tr> <TR> <TD><B>parens</b></td> <TD>yes</td> </tr> <TR> <TD><B>paths</b></td> <TD>yes</td> </tr> <TR> <TD><B>maps</b></td> <TD>no</td> </tr> <TR> <TD><B>functions</b></td> <TD>make object! only</td> </tr> <TR> <TD><B>closures</b></td> <TD>make object! only</td> </tr> <TR> <TD><B>objects</b></td> <TD>no</td> </tr> <TR> <TD><B>errors</b></td> <TD>no</td> </tr> <TR> <TD><B>ports</b></td> <TD>no</td> </tr>
Internally, there are also a few places where special copy operations occur. They are:
- COPY - as described above
- MAKE object! - copies with deep and bind modes.
- BIND/copy - deep copies before rebinding
- TAKE/deep - deep copies the result block (NOTE: this should be removed, because in general this should be done with a COPY/deep of the result!)
- MAKE function! - deep copies when parent function is provided as the source (MAKE parent-func! [...]).
- COPY function! - deep copies the source function
- REFLECT function! - deep copies body and/or spec to avoid manipulation of function internals
- evaluation of closure! - deep copies the function body to rebind variables
- some iterators - deep copy their code blocks to allow rebinding of loop related variables. They are: REPEAT, FOR, FOREACH, REMOVE-EACH, and MAP-EACH. But note, the FORALL, FORSKIP, and FOREVER functions do not deep copy.
- DO task! - deep copies the task body to avoid environment collisions