diff options
author | flywind <xzsflywind@gmail.com> | 2021-03-02 20:05:04 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-02 13:05:04 +0100 |
commit | 0efd96956966097d2927e2d2378d61e9f0d387ae (patch) | |
tree | 3d1885c9950d8f35f87e90cea863b7d1ece0fbc2 /doc/destructors.rst | |
parent | f1bf672ffc48b74170292edca3969de2f9bae707 (diff) | |
download | Nim-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.rst | 70 |
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. |