diff options
author | Araq <rumpf_a@web.de> | 2020-05-25 15:46:55 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2020-05-30 19:50:11 +0200 |
commit | 984af3d64e875016cf00dd2580b0b51f192e1fcd (patch) | |
tree | 661bcbdbe512f866c98aeeae8a24c0d864c4b808 /doc | |
parent | 52c3633223005f70bb4ecffa9f86b2e4e845e4a3 (diff) | |
download | Nim-984af3d64e875016cf00dd2580b0b51f192e1fcd.tar.gz |
document NVRO and exception handling
Diffstat (limited to 'doc')
-rw-r--r-- | doc/manual.rst | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/doc/manual.rst b/doc/manual.rst index 1472dd4e6..2b9c2b65c 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -3711,6 +3711,71 @@ location is derived from the second parameter (called ``varTy[T, 2]`` which is incompatible with ``varTy[T, 1]``. +NRVO +---- + +The return value is represented inside the body of a routine as the special +`result`:idx: variable. This allows for a mechanism much like C++'s +"named return value optimization" (`NRVO`:idx:). NRVO means that the stores +to ``result`` inside ``p`` directly affect the destination ``dest`` +in ``let/var dest = p(args)`` (definition of ``dest``) and also in ``dest = p(args)`` +(assignment to ``dest``). This is achieved by rewriting ``dest = p(args)`` +to ``p'(args, dest)`` where ``p'`` is a variation of ``p`` that returns ``void`` and +receives a hidden mutable parameter representing ``result``. + +Informally: + +.. code-block:: nim + proc p(): BigT = ... + + var x = p() + x = p() + + # is roughly turned into: + + proc p(result: var BigT) = ... + + var x; p(x) + p(x) + + +Let ``T``'s be ``p``'s return type. NRVO applies for ``T`` +if ``sizeof(T) >= N`` (where ``N`` is implementation dependent), +in other words, it applies for "big" structures. + +If ``p`` can raise an exception, NRVO applies regardless. This can produce +observable differences in behavior: + +.. code-block:: nim + + type + BigT = array[16, int] + + proc p(raiseAt: int): BigT = + for i in 0..high(result): + if i == raiseAt: raise newException(ValueError, "interception") + result[i] = i + + proc main = + var x: BigT + try: + x = p(8) + except ValueError: + doAssert x == [0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0] + + main() + + +However, the current implementation produces a warning in these cases. +There are different ways to deal with this warning: + +1. Disable the warning via ``{.push warning[ObservableStores]: off.}`` ... ``{.pop.}``. + Then one may need to ensure that ``p`` only raises *before* any stores to ``result`` + happen. + +2. One can use a temporary helper variable, for example instead of ``x = p(8)`` + use ``let tmp = p(8); x = tmp``. + Overloading of the subscript operator ------------------------------------- |