summary refs log tree commit diff stats
path: root/doc/destructors.rst
diff options
context:
space:
mode:
authorflywind <xzsflywind@gmail.com>2021-03-02 20:05:04 +0800
committerGitHub <noreply@github.com>2021-03-02 13:05:04 +0100
commit0efd96956966097d2927e2d2378d61e9f0d387ae (patch)
tree3d1885c9950d8f35f87e90cea863b7d1ece0fbc2 /doc/destructors.rst
parentf1bf672ffc48b74170292edca3969de2f9bae707 (diff)
downloadNim-0efd96956966097d2927e2d2378d61e9f0d387ae.tar.gz
document copy on write behavior of string literals in arc/orc (#17224)
* Update doc/destructors.rst

Co-authored-by: Juan Carlos <juancarlospaco@gmail.com>
Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
Diffstat (limited to 'doc/destructors.rst')
-rw-r--r--doc/destructors.rst70
1 files changed, 70 insertions, 0 deletions
diff --git a/doc/destructors.rst b/doc/destructors.rst
index cc483026f..3c50241eb 100644
--- a/doc/destructors.rst
+++ b/doc/destructors.rst
@@ -632,3 +632,73 @@ used to specialize the object traversal in order to avoid deep recursions:
 
 As can be seen from the example, this solution is hardly sufficient and
 should eventually be replaced by a better solution.
+
+
+Copy on write
+=============
+
+String literals are implemented as [copy-on-write](https://en.wikipedia.org/wiki/Copy-on-write).
+When assigning a string literal to a variable, a copy of the literal won't be created.
+Instead the variable simply points to the literal.
+The literal is shared between different variables which are pointing to it.
+The copy operation is deferred until the first write.
+
+```nim
+var x = "abc"  # no copy
+var y = x      # no copy
+```
+
+The string literal "abc" is stored in static memory and not allocated on the heap.
+The variable `x` points to the literal and the variable `y` points to the literal too.
+There is no copy during assigning operations.
+
+```nim
+var x = "abc"  # no copy
+var y = x      # no copy
+y[0] = 'h'     # copy
+```
+
+The program above shows when the copy operations happen.
+When mutating the variable `y`, the Nim compiler creates a fresh copy of `x`, 
+the variable `y` won't point to the string literal anymore. 
+Instead it points to the copy of `x` of which the memory can be mutated 
+and the variable `y` becomes a mutable string.
+
+.. Note:: The abstraction fails for `addr x` because whether the address is going to be used for mutations is unknown. 
+
+Let's look at a silly example demonstrating this behaviour:
+
+```nim
+var x = "abc"
+var y = x
+
+moveMem(addr y[0], addr x[0], 3)
+```
+
+The program fails because we need to prepare a fresh copy for the variable `y`.
+`prepareStrMutation` should be called before the address operation.
+
+```nim
+var x = "abc"
+var y = x
+
+prepareStrMutation(y)
+moveMem(addr y[0], addr x[0], 3)
+assert y == "abc"
+```
+
+Now `prepareStrMutation` solves the problem.
+It manually creates a fresh copy and makes the variable `y` mutable.
+
+```nim
+var x = "abc"
+var y = x
+
+prepareStrMutation(y)
+moveMem(addr y[0], addr x[0], 3)
+moveMem(addr y[0], addr x[0], 3)
+moveMem(addr y[0], addr x[0], 3)
+assert y == "abc"
+```
+
+No matter how many times `moveMem` is called, the program compiles and runs.