Markdown code blocks part 3 (#20117)
No logic was added, just 4 more files migrated.
This commit is contained in:
parent
2aeb0d516b
commit
a34dd3d77a
5 changed files with 409 additions and 283 deletions
400
doc/astspec.txt
400
doc/astspec.txt
File diff suppressed because it is too large
Load diff
|
|
@ -57,11 +57,11 @@ project. This allows you to take the generated code and place it directly
|
||||||
into a project using any of these languages. Here are some typical command-
|
into a project using any of these languages. Here are some typical command-
|
||||||
line invocations:
|
line invocations:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
nim c hallo.nim
|
||||||
nim c hallo.nim
|
nim cpp hallo.nim
|
||||||
nim cpp hallo.nim
|
nim objc hallo.nim
|
||||||
nim objc hallo.nim
|
```
|
||||||
|
|
||||||
The compiler commands select the target backend, but if needed you can
|
The compiler commands select the target backend, but if needed you can
|
||||||
`specify additional switches for cross-compilation
|
`specify additional switches for cross-compilation
|
||||||
|
|
@ -99,9 +99,9 @@ default is a ``.js`` file that is supposed to be referenced in an ``.html``
|
||||||
file. However, you can also run the code with `nodejs`:idx:
|
file. However, you can also run the code with `nodejs`:idx:
|
||||||
(`<http://nodejs.org>`_):
|
(`<http://nodejs.org>`_):
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
nim js -d:nodejs -r examples/hallo.nim
|
nim js -d:nodejs -r examples/hallo.nim
|
||||||
|
```
|
||||||
|
|
||||||
If you experience errors saying that `globalThis` is not defined, be
|
If you experience errors saying that `globalThis` is not defined, be
|
||||||
sure to run a recent version of Node.js (at least 12.0).
|
sure to run a recent version of Node.js (at least 12.0).
|
||||||
|
|
@ -159,21 +159,22 @@ interface.
|
||||||
|
|
||||||
Create a ``logic.c`` file with the following content:
|
Create a ``logic.c`` file with the following content:
|
||||||
|
|
||||||
.. code-block:: c
|
```c
|
||||||
int addTwoIntegers(int a, int b)
|
int addTwoIntegers(int a, int b)
|
||||||
{
|
{
|
||||||
return a + b;
|
return a + b;
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Create a ``calculator.nim`` file with the following content:
|
Create a ``calculator.nim`` file with the following content:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
{.compile: "logic.c".}
|
{.compile: "logic.c".}
|
||||||
proc addTwoIntegers(a, b: cint): cint {.importc.}
|
proc addTwoIntegers(a, b: cint): cint {.importc.}
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
echo addTwoIntegers(3, 7)
|
echo addTwoIntegers(3, 7)
|
||||||
|
```
|
||||||
|
|
||||||
With these two files in place, you can run `nim c -r calculator.nim`:cmd: and
|
With these two files in place, you can run `nim c -r calculator.nim`:cmd: and
|
||||||
the Nim compiler will compile the ``logic.c`` file in addition to
|
the Nim compiler will compile the ``logic.c`` file in addition to
|
||||||
|
|
@ -182,11 +183,11 @@ run. Another way to link the C file statically and get the same effect would
|
||||||
be to remove the line with the `compile` pragma and run the following
|
be to remove the line with the `compile` pragma and run the following
|
||||||
typical Unix commands:
|
typical Unix commands:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
gcc -c logic.c
|
||||||
gcc -c logic.c
|
ar rvs mylib.a logic.o
|
||||||
ar rvs mylib.a logic.o
|
nim c --passL:mylib.a -r calculator.nim
|
||||||
nim c --passL:mylib.a -r calculator.nim
|
```
|
||||||
|
|
||||||
Just like in this example we pass the path to the ``mylib.a`` library (and we
|
Just like in this example we pass the path to the ``mylib.a`` library (and we
|
||||||
could as well pass ``logic.o``) we could be passing switches to link any other
|
could as well pass ``logic.o``) we could be passing switches to link any other
|
||||||
|
|
@ -212,12 +213,12 @@ Create a ``host.html`` file with the following content:
|
||||||
Create a ``calculator.nim`` file with the following content (or reuse the one
|
Create a ``calculator.nim`` file with the following content (or reuse the one
|
||||||
from the previous section):
|
from the previous section):
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc addTwoIntegers(a, b: int): int {.importc.}
|
proc addTwoIntegers(a, b: int): int {.importc.}
|
||||||
|
|
||||||
when isMainModule:
|
when isMainModule:
|
||||||
echo addTwoIntegers(3, 7)
|
echo addTwoIntegers(3, 7)
|
||||||
|
```
|
||||||
|
|
||||||
Compile the Nim code to JavaScript with `nim js -o:calculator.js
|
Compile the Nim code to JavaScript with `nim js -o:calculator.js
|
||||||
calculator.nim`:cmd: and open ``host.html`` in a browser. If the browser supports
|
calculator.nim`:cmd: and open ``host.html`` in a browser. If the browser supports
|
||||||
|
|
@ -253,18 +254,17 @@ Use `--nimMainPrefix:MyLib` and the function to call is named `MyLibNimMain`.
|
||||||
|
|
||||||
Create a ``fib.nim`` file with the following content:
|
Create a ``fib.nim`` file with the following content:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc fib(a: cint): cint {.exportc.} =
|
proc fib(a: cint): cint {.exportc.} =
|
||||||
if a <= 2:
|
if a <= 2:
|
||||||
result = 1
|
result = 1
|
||||||
else:
|
else:
|
||||||
result = fib(a - 1) + fib(a - 2)
|
result = fib(a - 1) + fib(a - 2)
|
||||||
|
```
|
||||||
|
|
||||||
Create a ``maths.c`` file with the following content:
|
Create a ``maths.c`` file with the following content:
|
||||||
|
|
||||||
.. code-block:: c
|
```c
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int fib(int a);
|
int fib(int a);
|
||||||
|
|
@ -277,15 +277,16 @@ Create a ``maths.c`` file with the following content:
|
||||||
printf("Fib of %d is %d\n", f, fib(f));
|
printf("Fib of %d is %d\n", f, fib(f));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Now you can run the following Unix like commands to first generate C sources
|
Now you can run the following Unix like commands to first generate C sources
|
||||||
from the Nim code, then link them into a static binary along your main C
|
from the Nim code, then link them into a static binary along your main C
|
||||||
program:
|
program:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
nim c --noMain --noLinking fib.nim
|
nim c --noMain --noLinking fib.nim
|
||||||
gcc -o m -I$HOME/.cache/nim/fib_d -Ipath/to/nim/lib $HOME/.cache/nim/fib_d/*.c maths.c
|
gcc -o m -I$HOME/.cache/nim/fib_d -Ipath/to/nim/lib $HOME/.cache/nim/fib_d/*.c maths.c
|
||||||
|
```
|
||||||
|
|
||||||
The first command runs the Nim compiler with three special options to avoid
|
The first command runs the Nim compiler with three special options to avoid
|
||||||
generating a `main()`:c: function in the generated files and to avoid linking the
|
generating a `main()`:c: function in the generated files and to avoid linking the
|
||||||
|
|
@ -297,10 +298,10 @@ have to tell the C compiler where to find Nim's ``nimbase.h`` header file.
|
||||||
Instead of depending on the generation of the individual ``.c`` files you can
|
Instead of depending on the generation of the individual ``.c`` files you can
|
||||||
also ask the Nim compiler to generate a statically linked library:
|
also ask the Nim compiler to generate a statically linked library:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
nim c --app:staticLib --noMain fib.nim
|
nim c --app:staticLib --noMain fib.nim
|
||||||
gcc -o m -Inimcache -Ipath/to/nim/lib maths.c libfib.nim.a
|
gcc -o m -Inimcache -Ipath/to/nim/lib maths.c libfib.nim.a
|
||||||
|
```
|
||||||
|
|
||||||
The Nim compiler will handle linking the source files generated in the
|
The Nim compiler will handle linking the source files generated in the
|
||||||
``nimcache`` directory into the ``libfib.nim.a`` static library, which you can
|
``nimcache`` directory into the ``libfib.nim.a`` static library, which you can
|
||||||
|
|
@ -313,25 +314,25 @@ use `-ldl`:option: too to link in required dlopen functionality.
|
||||||
|
|
||||||
Create a ``mhost.html`` file with the following content:
|
Create a ``mhost.html`` file with the following content:
|
||||||
|
|
||||||
.. code-block::
|
```
|
||||||
|
|
||||||
<html><body>
|
<html><body>
|
||||||
<script type="text/javascript" src="fib.js"></script>
|
<script type="text/javascript" src="fib.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
alert("Fib for 9 is " + fib(9));
|
alert("Fib for 9 is " + fib(9));
|
||||||
</script>
|
</script>
|
||||||
</body></html>
|
</body></html>
|
||||||
|
```
|
||||||
|
|
||||||
Create a ``fib.nim`` file with the following content (or reuse the one
|
Create a ``fib.nim`` file with the following content (or reuse the one
|
||||||
from the previous section):
|
from the previous section):
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc fib(a: cint): cint {.exportc.} =
|
proc fib(a: cint): cint {.exportc.} =
|
||||||
if a <= 2:
|
if a <= 2:
|
||||||
result = 1
|
result = 1
|
||||||
else:
|
else:
|
||||||
result = fib(a - 1) + fib(a - 2)
|
result = fib(a - 1) + fib(a - 2)
|
||||||
|
```
|
||||||
|
|
||||||
Compile the Nim code to JavaScript with `nim js -o:fib.js fib.nim`:cmd: and
|
Compile the Nim code to JavaScript with `nim js -o:fib.js fib.nim`:cmd: and
|
||||||
open ``mhost.html`` in a browser. If the browser supports javascript, you
|
open ``mhost.html`` in a browser. If the browser supports javascript, you
|
||||||
|
|
@ -378,10 +379,10 @@ from being freed with `GC_ref <system.html#GC_ref,string>`_ and `GC_unref
|
||||||
A similar thing happens with C code invoking Nim code which returns a
|
A similar thing happens with C code invoking Nim code which returns a
|
||||||
`cstring`. Consider the following proc:
|
`cstring`. Consider the following proc:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc gimme(): cstring {.exportc.} =
|
proc gimme(): cstring {.exportc.} =
|
||||||
result = "Hey there C code! " & $rand(100)
|
result = "Hey there C code! " & $rand(100)
|
||||||
|
```
|
||||||
|
|
||||||
Since Nim's reference counting mechanism is not aware of the C code, once the
|
Since Nim's reference counting mechanism is not aware of the C code, once the
|
||||||
`gimme` proc has finished it can reclaim the memory of the `cstring`.
|
`gimme` proc has finished it can reclaim the memory of the `cstring`.
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,7 @@ things like `echo "done"`. Don't use `unittest.suite` and `unittest.test`.
|
||||||
|
|
||||||
Sample test:
|
Sample test:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
block: # foo
|
block: # foo
|
||||||
doAssert foo(1) == 10
|
doAssert foo(1) == 10
|
||||||
|
|
||||||
|
|
@ -76,6 +75,7 @@ Sample test:
|
||||||
@[false, false], @[false, false]]
|
@[false, false], @[false, false]]
|
||||||
# doAssert with `not` can now be done as follows:
|
# doAssert with `not` can now be done as follows:
|
||||||
doAssert not (1 == 2)
|
doAssert not (1 == 2)
|
||||||
|
```
|
||||||
|
|
||||||
Always refer to a GitHub issue using the following exact syntax: ``bug #1234`` as shown
|
Always refer to a GitHub issue using the following exact syntax: ``bug #1234`` as shown
|
||||||
above, so that it's consistent and easier to search or for tooling. Some browser
|
above, so that it's consistent and easier to search or for tooling. Some browser
|
||||||
|
|
@ -110,8 +110,7 @@ For a full spec, see here: ``testament/specs.nim``
|
||||||
|
|
||||||
An example of a test:
|
An example of a test:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
discard """
|
discard """
|
||||||
errormsg: "type mismatch: got (PTest)"
|
errormsg: "type mismatch: got (PTest)"
|
||||||
"""
|
"""
|
||||||
|
|
@ -123,6 +122,7 @@ An example of a test:
|
||||||
|
|
||||||
var buf: PTest
|
var buf: PTest
|
||||||
buf.test()
|
buf.test()
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Running tests
|
Running tests
|
||||||
|
|
@ -130,9 +130,9 @@ Running tests
|
||||||
|
|
||||||
You can run the tests with
|
You can run the tests with
|
||||||
|
|
||||||
.. code-block:: cmd
|
```cmd
|
||||||
|
|
||||||
./koch tests
|
./koch tests
|
||||||
|
```
|
||||||
|
|
||||||
which will run a good subset of tests. Some tests may fail. If you
|
which will run a good subset of tests. Some tests may fail. If you
|
||||||
only want to see the output of failing tests, go for
|
only want to see the output of failing tests, go for
|
||||||
|
|
@ -145,17 +145,17 @@ You can also run only a single category of tests. A category is a subdirectory
|
||||||
in the ``tests/`` directory. There are a couple of special categories; for a
|
in the ``tests/`` directory. There are a couple of special categories; for a
|
||||||
list of these, see ``testament/categories.nim``, at the bottom.
|
list of these, see ``testament/categories.nim``, at the bottom.
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
./koch tests c lib # compiles / runs stdlib modules, including `isMainModule` tests
|
./koch tests c lib # compiles / runs stdlib modules, including `isMainModule` tests
|
||||||
./koch tests c megatest # runs a set of tests that can be combined into 1
|
./koch tests c megatest # runs a set of tests that can be combined into 1
|
||||||
|
```
|
||||||
|
|
||||||
To run a single test:
|
To run a single test:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
./koch test run <category>/<name> # e.g.: tuples/ttuples_issues
|
./koch test run <category>/<name> # e.g.: tuples/ttuples_issues
|
||||||
./koch test run tests/stdlib/tos.nim # can also provide relative path
|
./koch test run tests/stdlib/tos.nim # can also provide relative path
|
||||||
|
```
|
||||||
|
|
||||||
For reproducible tests (to reproduce an environment more similar to the one
|
For reproducible tests (to reproduce an environment more similar to the one
|
||||||
run by Continuous Integration on github actions/azure pipelines), you may want to disable your
|
run by Continuous Integration on github actions/azure pipelines), you may want to disable your
|
||||||
|
|
@ -174,25 +174,25 @@ The tester can compare two test runs. First, you need to create a
|
||||||
reference test. You'll also need to the commit id, because that's what
|
reference test. You'll also need to the commit id, because that's what
|
||||||
the tester needs to know in order to compare the two.
|
the tester needs to know in order to compare the two.
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
git checkout devel
|
git checkout devel
|
||||||
DEVEL_COMMIT=$(git rev-parse HEAD)
|
DEVEL_COMMIT=$(git rev-parse HEAD)
|
||||||
./koch tests
|
./koch tests
|
||||||
|
```
|
||||||
|
|
||||||
Then switch over to your changes and run the tester again.
|
Then switch over to your changes and run the tester again.
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
git checkout your-changes
|
git checkout your-changes
|
||||||
./koch tests
|
./koch tests
|
||||||
|
```
|
||||||
|
|
||||||
Then you can ask the tester to create a ``testresults.html`` which will
|
Then you can ask the tester to create a ``testresults.html`` which will
|
||||||
tell you if any new tests passed/failed.
|
tell you if any new tests passed/failed.
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
|
||||||
./koch tests --print html $DEVEL_COMMIT
|
./koch tests --print html $DEVEL_COMMIT
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Deprecation
|
Deprecation
|
||||||
|
|
@ -201,8 +201,7 @@ Deprecation
|
||||||
Backward compatibility is important, so instead of a rename you need to deprecate
|
Backward compatibility is important, so instead of a rename you need to deprecate
|
||||||
the old name and introduce a new name:
|
the old name and introduce a new name:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
# for routines (proc/template/macro/iterator) and types:
|
# for routines (proc/template/macro/iterator) and types:
|
||||||
proc oldProc(a: int, b: float): bool {.deprecated:
|
proc oldProc(a: int, b: float): bool {.deprecated:
|
||||||
"deprecated since v1.2.3; use `newImpl: string -> int` instead".} = discard
|
"deprecated since v1.2.3; use `newImpl: string -> int` instead".} = discard
|
||||||
|
|
@ -214,6 +213,7 @@ the old name and introduce a new name:
|
||||||
# (likewise with object types and their fields):
|
# (likewise with object types and their fields):
|
||||||
type Bar {.deprecated.} = enum bar0, bar1
|
type Bar {.deprecated.} = enum bar0, bar1
|
||||||
type Barz = enum baz0, baz1 {.deprecated.}, baz2
|
type Barz = enum baz0, baz1 {.deprecated.}, baz2
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
See also `Deprecated <manual.html#pragmas-deprecated-pragma>`_
|
See also `Deprecated <manual.html#pragmas-deprecated-pragma>`_
|
||||||
|
|
@ -234,12 +234,13 @@ test cases (typically 1 to 3 `assert` statements, depending on complexity).
|
||||||
These `runnableExamples` are automatically run by `nim doc mymodule.nim`:cmd:
|
These `runnableExamples` are automatically run by `nim doc mymodule.nim`:cmd:
|
||||||
as well as `testament`:cmd: and guarantee they stay in sync.
|
as well as `testament`:cmd: and guarantee they stay in sync.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
proc addBar*(a: string): string =
|
proc addBar*(a: string): string =
|
||||||
## Adds "Bar" to `a`.
|
## Adds "Bar" to `a`.
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
assert "baz".addBar == "bazBar"
|
assert "baz".addBar == "bazBar"
|
||||||
result = a & "Bar"
|
result = a & "Bar"
|
||||||
|
```
|
||||||
|
|
||||||
See `parentDir <os.html#parentDir,string>`_ example.
|
See `parentDir <os.html#parentDir,string>`_ example.
|
||||||
|
|
||||||
|
|
@ -247,47 +248,49 @@ The RestructuredText Nim uses has a special syntax for including code snippets
|
||||||
embedded in documentation; these are not run by `nim doc`:cmd: and therefore are
|
embedded in documentation; these are not run by `nim doc`:cmd: and therefore are
|
||||||
not guaranteed to stay in sync, so `runnableExamples` is almost always preferred:
|
not guaranteed to stay in sync, so `runnableExamples` is almost always preferred:
|
||||||
|
|
||||||
.. code-block:: nim
|
````nim
|
||||||
|
|
||||||
proc someProc*(): string =
|
proc someProc*(): string =
|
||||||
## Returns "something"
|
## Returns "something"
|
||||||
##
|
##
|
||||||
## .. code-block::
|
## ```
|
||||||
## echo someProc() # "something"
|
## echo someProc() # "something"
|
||||||
|
## ```
|
||||||
result = "something" # single-hash comments do not produce documentation
|
result = "something" # single-hash comments do not produce documentation
|
||||||
|
````
|
||||||
|
|
||||||
The ``.. code-block:: nim`` followed by a newline and an indentation instructs the
|
The \`\`\` followed by a newline and an indentation instructs the
|
||||||
`nim doc`:cmd: command to produce syntax-highlighted example code with the
|
`nim doc`:cmd: command to produce syntax-highlighted example code with the
|
||||||
documentation (``.. code-block::`` is sufficient from inside a nim module).
|
documentation (\`\`\` is sufficient inside a ``.nim`` module, while from
|
||||||
|
a ``.md`` one needs to set the language explicitly as \`\`\`nim).
|
||||||
|
|
||||||
When forward declaration is used, the documentation should be included with the
|
When forward declaration is used, the documentation should be included with the
|
||||||
first appearance of the proc.
|
first appearance of the proc.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc hello*(): string
|
proc hello*(): string
|
||||||
## Put documentation here
|
## Put documentation here
|
||||||
proc nothing() = discard
|
proc nothing() = discard
|
||||||
proc hello*(): string =
|
proc hello*(): string =
|
||||||
## ignore this
|
## ignore this
|
||||||
echo "hello"
|
echo "hello"
|
||||||
|
```
|
||||||
|
|
||||||
The preferred documentation style is to begin with a capital letter and use
|
The preferred documentation style is to begin with a capital letter and use
|
||||||
the third-person singular. That is, between:
|
the third-person singular. That is, between:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc hello*(): string =
|
proc hello*(): string =
|
||||||
## Returns "hello"
|
## Returns "hello"
|
||||||
result = "hello"
|
result = "hello"
|
||||||
|
```
|
||||||
|
|
||||||
or
|
or
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc hello*(): string =
|
proc hello*(): string =
|
||||||
## say hello
|
## say hello
|
||||||
result = "hello"
|
result = "hello"
|
||||||
|
```
|
||||||
|
|
||||||
the first is preferred.
|
the first is preferred.
|
||||||
|
|
||||||
|
|
@ -296,8 +299,9 @@ in the postfix form for uniformity, that is after \`text in backticks\`.
|
||||||
For example an ``:idx:`` role for referencing a topic ("SQLite" in the
|
For example an ``:idx:`` role for referencing a topic ("SQLite" in the
|
||||||
example below) from `Nim Index`_ can be used in doc comment this way:
|
example below) from `Nim Index`_ can be used in doc comment this way:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
## A higher level `SQLite`:idx: database wrapper.
|
## A higher level `SQLite`:idx: database wrapper.
|
||||||
|
```
|
||||||
|
|
||||||
.. _`Nim Index`: https://nim-lang.org/docs/theindex.html
|
.. _`Nim Index`: https://nim-lang.org/docs/theindex.html
|
||||||
|
|
||||||
|
|
@ -355,50 +359,50 @@ New `defined(foo)` symbols need to be prefixed by the nimble package name, or
|
||||||
by `nim` for symbols in nim sources (e.g. compiler, standard library). This is
|
by `nim` for symbols in nim sources (e.g. compiler, standard library). This is
|
||||||
to avoid name conflicts across packages.
|
to avoid name conflicts across packages.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
# if in nim sources
|
# if in nim sources
|
||||||
when defined(allocStats): discard # bad, can cause conflicts
|
when defined(allocStats): discard # bad, can cause conflicts
|
||||||
when defined(nimAllocStats): discard # preferred
|
when defined(nimAllocStats): discard # preferred
|
||||||
# if in a package `cligen`:
|
# if in a package `cligen`:
|
||||||
when defined(debug): discard # bad, can cause conflicts
|
when defined(debug): discard # bad, can cause conflicts
|
||||||
when defined(cligenDebug): discard # preferred
|
when defined(cligenDebug): discard # preferred
|
||||||
|
```
|
||||||
|
|
||||||
.. _noimplicitbool:
|
.. _noimplicitbool:
|
||||||
Take advantage of no implicit bool conversion
|
Take advantage of no implicit bool conversion
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
doAssert isValid() == true
|
doAssert isValid() == true
|
||||||
doAssert isValid() # preferred
|
doAssert isValid() # preferred
|
||||||
|
```
|
||||||
|
|
||||||
.. _design_for_mcs:
|
.. _design_for_mcs:
|
||||||
Design with method call syntax chaining in mind
|
Design with method call syntax chaining in mind
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc foo(cond: bool, lines: seq[string]) # bad
|
proc foo(cond: bool, lines: seq[string]) # bad
|
||||||
proc foo(lines: seq[string], cond: bool) # preferred
|
proc foo(lines: seq[string], cond: bool) # preferred
|
||||||
# can be called as: `getLines().foo(false)`
|
# can be called as: `getLines().foo(false)`
|
||||||
|
```
|
||||||
|
|
||||||
.. _avoid_quit:
|
.. _avoid_quit:
|
||||||
Use exceptions (including `assert` / `doAssert`) instead of `quit`
|
Use exceptions (including `assert` / `doAssert`) instead of `quit`
|
||||||
rationale: https://forum.nim-lang.org/t/4089
|
rationale: https://forum.nim-lang.org/t/4089
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
quit() # bad in almost all cases
|
quit() # bad in almost all cases
|
||||||
doAssert() # preferred
|
doAssert() # preferred
|
||||||
|
```
|
||||||
|
|
||||||
.. _tests_use_doAssert:
|
.. _tests_use_doAssert:
|
||||||
Use `doAssert` (or `unittest.check`, `unittest.require`), not `assert` in all
|
Use `doAssert` (or `unittest.check`, `unittest.require`), not `assert` in all
|
||||||
tests so they'll be enabled even with `--assertions:off`:option:.
|
tests so they'll be enabled even with `--assertions:off`:option:.
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
block: # foo
|
block: # foo
|
||||||
assert foo() # bad
|
assert foo() # bad
|
||||||
doAssert foo() # preferred
|
doAssert foo() # preferred
|
||||||
|
```
|
||||||
|
|
||||||
.. _runnableExamples_use_assert:
|
.. _runnableExamples_use_assert:
|
||||||
An exception to the above rule is `runnableExamples` and ``code-block`` rst blocks
|
An exception to the above rule is `runnableExamples` and ``code-block`` rst blocks
|
||||||
|
|
@ -407,33 +411,33 @@ instead of `doAssert`. Note that `nim doc -d:danger main`:cmd: won't pass `-d:da
|
||||||
`runnableExamples`, but `nim doc --doccmd:-d:danger main`:cmd: would, and so would the
|
`runnableExamples`, but `nim doc --doccmd:-d:danger main`:cmd: would, and so would the
|
||||||
second example below:
|
second example below:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
runnableExamples:
|
runnableExamples:
|
||||||
doAssert foo() # bad
|
doAssert foo() # bad
|
||||||
assert foo() # preferred
|
assert foo() # preferred
|
||||||
|
|
||||||
runnableExamples("-d:danger"):
|
runnableExamples("-d:danger"):
|
||||||
doAssert foo() # `assert` would be disabled here, so `doAssert` makes more sense
|
doAssert foo() # `assert` would be disabled here, so `doAssert` makes more sense
|
||||||
|
```
|
||||||
|
|
||||||
.. _delegate_printing:
|
.. _delegate_printing:
|
||||||
Delegate printing to caller: return `string` instead of calling `echo`
|
Delegate printing to caller: return `string` instead of calling `echo`
|
||||||
rationale: it's more flexible (e.g. allows the caller to call custom printing,
|
rationale: it's more flexible (e.g. allows the caller to call custom printing,
|
||||||
including prepending location info, writing to log files, etc).
|
including prepending location info, writing to log files, etc).
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc foo() = echo "bar" # bad
|
proc foo() = echo "bar" # bad
|
||||||
proc foo(): string = "bar" # preferred (usually)
|
proc foo(): string = "bar" # preferred (usually)
|
||||||
|
```
|
||||||
|
|
||||||
.. _use_Option:
|
.. _use_Option:
|
||||||
[Ongoing debate] Consider using Option instead of return bool + var argument,
|
[Ongoing debate] Consider using Option instead of return bool + var argument,
|
||||||
unless stack allocation is needed (e.g. for efficiency).
|
unless stack allocation is needed (e.g. for efficiency).
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc foo(a: var Bar): bool
|
proc foo(a: var Bar): bool
|
||||||
proc foo(): Option[Bar]
|
proc foo(): Option[Bar]
|
||||||
|
```
|
||||||
|
|
||||||
.. _use_doAssert_not_echo:
|
.. _use_doAssert_not_echo:
|
||||||
Tests (including in testament) should always prefer assertions over `echo`,
|
Tests (including in testament) should always prefer assertions over `echo`,
|
||||||
|
|
@ -441,10 +445,10 @@ except when that's not possible. It's more precise, easier for readers and
|
||||||
maintainers to where expected values refer to. See for example
|
maintainers to where expected values refer to. See for example
|
||||||
https://github.com/nim-lang/Nim/pull/9335 and https://forum.nim-lang.org/t/4089
|
https://github.com/nim-lang/Nim/pull/9335 and https://forum.nim-lang.org/t/4089
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
echo foo() # adds a line for testament in `output:` block inside `discard`.
|
echo foo() # adds a line for testament in `output:` block inside `discard`.
|
||||||
doAssert foo() == [1, 2] # preferred, except when not possible to do so.
|
doAssert foo() == [1, 2] # preferred, except when not possible to do so.
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
The `git`:cmd: stuff
|
The `git`:cmd: stuff
|
||||||
|
|
@ -480,10 +484,10 @@ General commit rules
|
||||||
Always check your changes for whitespace errors using `git diff --check`:cmd:
|
Always check your changes for whitespace errors using `git diff --check`:cmd:
|
||||||
or add the following ``pre-commit`` hook:
|
or add the following ``pre-commit`` hook:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
#!/bin/sh
|
||||||
#!/bin/sh
|
git diff --check --cached || exit $?
|
||||||
git diff --check --cached || exit $?
|
```
|
||||||
5. Describe your commit and use your common sense.
|
5. Describe your commit and use your common sense.
|
||||||
Example commit message::
|
Example commit message::
|
||||||
|
|
||||||
|
|
@ -565,10 +569,10 @@ Code reviews
|
||||||
doesn't help much as it doesn't highlight moves. Instead, you can use something
|
doesn't help much as it doesn't highlight moves. Instead, you can use something
|
||||||
like this, see visual results `here <https://github.com/nim-lang/Nim/pull/10431#issuecomment-456968196>`_:
|
like this, see visual results `here <https://github.com/nim-lang/Nim/pull/10431#issuecomment-456968196>`_:
|
||||||
|
|
||||||
.. code:: cmd
|
```cmd
|
||||||
|
git fetch origin pull/10431/head && git checkout FETCH_HEAD
|
||||||
git fetch origin pull/10431/head && git checkout FETCH_HEAD
|
git diff --color-moved-ws=allow-indentation-change --color-moved=blocks HEAD^
|
||||||
git diff --color-moved-ws=allow-indentation-change --color-moved=blocks HEAD^
|
```
|
||||||
|
|
||||||
3. In addition, you can view GitHub-like diffs locally to identify what was changed
|
3. In addition, you can view GitHub-like diffs locally to identify what was changed
|
||||||
within a code block using `diff-highlight`:cmd: or `diff-so-fancy`:cmd:, e.g.:
|
within a code block using `diff-highlight`:cmd: or `diff-so-fancy`:cmd:, e.g.:
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,7 @@ Motivating example
|
||||||
With the language mechanisms described here, a custom seq could be
|
With the language mechanisms described here, a custom seq could be
|
||||||
written as:
|
written as:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
type
|
type
|
||||||
myseq*[T] = object
|
myseq*[T] = object
|
||||||
len, cap: int
|
len, cap: int
|
||||||
|
|
@ -91,7 +90,7 @@ written as:
|
||||||
for i in 0..<result.len: result.data[i] = elems[i]
|
for i in 0..<result.len: result.data[i] = elems[i]
|
||||||
|
|
||||||
proc len*[T](x: myseq[T]): int {.inline.} = x.len
|
proc len*[T](x: myseq[T]): int {.inline.} = x.len
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Lifetime-tracking hooks
|
Lifetime-tracking hooks
|
||||||
|
|
@ -119,20 +118,18 @@ to return.
|
||||||
|
|
||||||
The prototype of this hook for a type `T` needs to be:
|
The prototype of this hook for a type `T` needs to be:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc `=destroy`(x: var T)
|
proc `=destroy`(x: var T)
|
||||||
|
```
|
||||||
|
|
||||||
The general pattern in `=destroy` looks like:
|
The general pattern in `=destroy` looks like:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc `=destroy`(x: var T) =
|
proc `=destroy`(x: var T) =
|
||||||
# first check if 'x' was moved to somewhere else:
|
# first check if 'x' was moved to somewhere else:
|
||||||
if x.field != nil:
|
if x.field != nil:
|
||||||
freeResource(x.field)
|
freeResource(x.field)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
`=sink` hook
|
`=sink` hook
|
||||||
|
|
@ -149,20 +146,19 @@ provide `=destroy` and `=copy`, the compiler will take care of the rest.
|
||||||
|
|
||||||
The prototype of this hook for a type `T` needs to be:
|
The prototype of this hook for a type `T` needs to be:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc `=sink`(dest: var T; source: T)
|
proc `=sink`(dest: var T; source: T)
|
||||||
|
```
|
||||||
|
|
||||||
The general pattern in `=sink` looks like:
|
The general pattern in `=sink` looks like:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc `=sink`(dest: var T; source: T) =
|
proc `=sink`(dest: var T; source: T) =
|
||||||
`=destroy`(dest)
|
`=destroy`(dest)
|
||||||
wasMoved(dest)
|
wasMoved(dest)
|
||||||
dest.field = source.field
|
dest.field = source.field
|
||||||
|
```
|
||||||
|
|
||||||
**Note**: `=sink` does not need to check for self-assignments.
|
**Note**: `=sink` does not need to check for self-assignments.
|
||||||
How self-assignments are handled is explained later in this document.
|
How self-assignments are handled is explained later in this document.
|
||||||
|
|
@ -177,29 +173,27 @@ operations.
|
||||||
|
|
||||||
The prototype of this hook for a type `T` needs to be:
|
The prototype of this hook for a type `T` needs to be:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc `=copy`(dest: var T; source: T)
|
proc `=copy`(dest: var T; source: T)
|
||||||
|
```
|
||||||
|
|
||||||
The general pattern in `=copy` looks like:
|
The general pattern in `=copy` looks like:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc `=copy`(dest: var T; source: T) =
|
proc `=copy`(dest: var T; source: T) =
|
||||||
# protect against self-assignments:
|
# protect against self-assignments:
|
||||||
if dest.field != source.field:
|
if dest.field != source.field:
|
||||||
`=destroy`(dest)
|
`=destroy`(dest)
|
||||||
wasMoved(dest)
|
wasMoved(dest)
|
||||||
dest.field = duplicateResource(source.field)
|
dest.field = duplicateResource(source.field)
|
||||||
|
```
|
||||||
|
|
||||||
The `=copy` proc can be marked with the `{.error.}` pragma. Then any assignment
|
The `=copy` proc can be marked with the `{.error.}` pragma. Then any assignment
|
||||||
that otherwise would lead to a copy is prevented at compile-time. This looks like:
|
that otherwise would lead to a copy is prevented at compile-time. This looks like:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc `=copy`(dest: var T; source: T) {.error.}
|
proc `=copy`(dest: var T; source: T) {.error.}
|
||||||
|
```
|
||||||
|
|
||||||
but a custom error message (e.g., `{.error: "custom error".}`) will not be emitted
|
but a custom error message (e.g., `{.error: "custom error".}`) will not be emitted
|
||||||
by the compiler. Notice that there is no `=` before the `{.error.}` pragma.
|
by the compiler. Notice that there is no `=` before the `{.error.}` pragma.
|
||||||
|
|
@ -215,9 +209,9 @@ memory or resources, but memory safety is not compromised.
|
||||||
|
|
||||||
The prototype of this hook for a type `T` needs to be:
|
The prototype of this hook for a type `T` needs to be:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc `=trace`(dest: var T; env: pointer)
|
proc `=trace`(dest: var T; env: pointer)
|
||||||
|
```
|
||||||
|
|
||||||
`env` is used by ORC to keep track of its internal state, it should be passed around
|
`env` is used by ORC to keep track of its internal state, it should be passed around
|
||||||
to calls of the built-in `=trace` operation.
|
to calls of the built-in `=trace` operation.
|
||||||
|
|
@ -233,8 +227,7 @@ prevent the automatic creation.
|
||||||
|
|
||||||
The general pattern in using `=destroy` with `=trace` looks like:
|
The general pattern in using `=destroy` with `=trace` looks like:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
type
|
type
|
||||||
Test[T] = object
|
Test[T] = object
|
||||||
size: Natural
|
size: Natural
|
||||||
|
|
@ -255,6 +248,7 @@ The general pattern in using `=destroy` with `=trace` looks like:
|
||||||
for i in 0 ..< dest.size: `=trace`(dest.arr[i], env)
|
for i in 0 ..< dest.size: `=trace`(dest.arr[i], env)
|
||||||
|
|
||||||
# following may be other custom "hooks" as required...
|
# following may be other custom "hooks" as required...
|
||||||
|
```
|
||||||
|
|
||||||
**Note**: The `=trace` hooks (which are only used by `--mm:orc`) are currently more experimental and less refined
|
**Note**: The `=trace` hooks (which are only used by `--mm:orc`) are currently more experimental and less refined
|
||||||
than the other hooks.
|
than the other hooks.
|
||||||
|
|
@ -307,8 +301,7 @@ not a linear type system.
|
||||||
The employed static analysis is limited and only concerned with local variables;
|
The employed static analysis is limited and only concerned with local variables;
|
||||||
however, object and tuple fields are treated as separate entities:
|
however, object and tuple fields are treated as separate entities:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc consume(x: sink Obj) = discard "no implementation"
|
proc consume(x: sink Obj) = discard "no implementation"
|
||||||
|
|
||||||
proc main =
|
proc main =
|
||||||
|
|
@ -316,16 +309,16 @@ however, object and tuple fields are treated as separate entities:
|
||||||
consume tup[0]
|
consume tup[0]
|
||||||
# ok, only tup[0] was consumed, tup[1] is still alive:
|
# ok, only tup[0] was consumed, tup[1] is still alive:
|
||||||
echo tup[1]
|
echo tup[1]
|
||||||
|
```
|
||||||
|
|
||||||
Sometimes it is required to explicitly `move` a value into its final position:
|
Sometimes it is required to explicitly `move` a value into its final position:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc main =
|
proc main =
|
||||||
var dest, src: array[10, string]
|
var dest, src: array[10, string]
|
||||||
# ...
|
# ...
|
||||||
for i in 0..high(dest): dest[i] = move(src[i])
|
for i in 0..high(dest): dest[i] = move(src[i])
|
||||||
|
```
|
||||||
|
|
||||||
An implementation is allowed, but not required to implement even more move
|
An implementation is allowed, but not required to implement even more move
|
||||||
optimizations (and the current implementation does not).
|
optimizations (and the current implementation does not).
|
||||||
|
|
@ -344,11 +337,10 @@ use `{.push sinkInference: on.}` ... `{.pop.}`.
|
||||||
The `.nosinks`:idx: pragma can be used to disable this inference
|
The `.nosinks`:idx: pragma can be used to disable this inference
|
||||||
for a single routine:
|
for a single routine:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc addX(x: T; child: T) {.nosinks.} =
|
proc addX(x: T; child: T) {.nosinks.} =
|
||||||
x.s.add child
|
x.s.add child
|
||||||
|
```
|
||||||
|
|
||||||
The details of the inference algorithm are currently undocumented.
|
The details of the inference algorithm are currently undocumented.
|
||||||
|
|
||||||
|
|
@ -456,8 +448,7 @@ The complex case looks like a variant of `x = f(x)`, we consider
|
||||||
`x = select(rand() < 0.5, x, y)` here:
|
`x = select(rand() < 0.5, x, y)` here:
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc select(cond: bool; a, b: sink string): string =
|
proc select(cond: bool; a, b: sink string): string =
|
||||||
if cond:
|
if cond:
|
||||||
result = a # moves a into result
|
result = a # moves a into result
|
||||||
|
|
@ -469,13 +460,11 @@ The complex case looks like a variant of `x = f(x)`, we consider
|
||||||
var y = "xyz"
|
var y = "xyz"
|
||||||
# possible self-assignment:
|
# possible self-assignment:
|
||||||
x = select(true, x, y)
|
x = select(true, x, y)
|
||||||
|
```
|
||||||
|
|
||||||
Is transformed into:
|
Is transformed into:
|
||||||
|
|
||||||
|
```nim
|
||||||
.. code-block:: nim
|
|
||||||
|
|
||||||
proc select(cond: bool; a, b: sink string): string =
|
proc select(cond: bool; a, b: sink string): string =
|
||||||
try:
|
try:
|
||||||
if cond:
|
if cond:
|
||||||
|
|
@ -506,6 +495,7 @@ Is transformed into:
|
||||||
finally:
|
finally:
|
||||||
`=destroy`(y)
|
`=destroy`(y)
|
||||||
`=destroy`(x)
|
`=destroy`(x)
|
||||||
|
```
|
||||||
|
|
||||||
As can be manually verified, this transformation is correct for
|
As can be manually verified, this transformation is correct for
|
||||||
self-assignments.
|
self-assignments.
|
||||||
|
|
@ -527,8 +517,7 @@ that the pointer does not outlive its origin. No destructor call is injected
|
||||||
for expressions of type `lent T` or of type `var T`.
|
for expressions of type `lent T` or of type `var T`.
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
type
|
type
|
||||||
Tree = object
|
Tree = object
|
||||||
kids: seq[Tree]
|
kids: seq[Tree]
|
||||||
|
|
@ -553,6 +542,7 @@ for expressions of type `lent T` or of type `var T`.
|
||||||
# everything turned into moves:
|
# everything turned into moves:
|
||||||
let t = construct(@[construct(@[]), construct(@[])])
|
let t = construct(@[construct(@[]), construct(@[])])
|
||||||
echo t[0] # accessor does not copy the element!
|
echo t[0] # accessor does not copy the element!
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
The cursor pragma
|
The cursor pragma
|
||||||
|
|
@ -564,12 +554,12 @@ This means that cyclic structures cannot be freed
|
||||||
immediately (`--mm:orc`:option: ships with a cycle collector).
|
immediately (`--mm:orc`:option: ships with a cycle collector).
|
||||||
With the `cursor` pragma one can break up cycles declaratively:
|
With the `cursor` pragma one can break up cycles declaratively:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
type
|
type
|
||||||
Node = ref object
|
Node = ref object
|
||||||
left: Node # owning ref
|
left: Node # owning ref
|
||||||
right {.cursor.}: Node # non-owning ref
|
right {.cursor.}: Node # non-owning ref
|
||||||
|
```
|
||||||
|
|
||||||
But please notice that this is not C++'s weak_ptr, it means the right field is not
|
But please notice that this is not C++'s weak_ptr, it means the right field is not
|
||||||
involved in the reference counting, it is a raw pointer without runtime checks.
|
involved in the reference counting, it is a raw pointer without runtime checks.
|
||||||
|
|
@ -578,13 +568,12 @@ Automatic reference counting also has the disadvantage that it introduces overhe
|
||||||
when iterating over linked structures. The `cursor` pragma can also be used
|
when iterating over linked structures. The `cursor` pragma can also be used
|
||||||
to avoid this overhead:
|
to avoid this overhead:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
var it {.cursor.} = listRoot
|
var it {.cursor.} = listRoot
|
||||||
while it != nil:
|
while it != nil:
|
||||||
use(it)
|
use(it)
|
||||||
it = it.next
|
it = it.next
|
||||||
|
```
|
||||||
|
|
||||||
In fact, `cursor` more generally prevents object construction/destruction pairs
|
In fact, `cursor` more generally prevents object construction/destruction pairs
|
||||||
and so can also be useful in other contexts. The alternative solution would be to
|
and so can also be useful in other contexts. The alternative solution would be to
|
||||||
|
|
@ -609,13 +598,13 @@ words, we do a compile-time copy-on-write analysis.
|
||||||
This means that "borrowed" views can be written naturally and without explicit pointer
|
This means that "borrowed" views can be written naturally and without explicit pointer
|
||||||
indirections:
|
indirections:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
proc main(tab: Table[string, string]) =
|
proc main(tab: Table[string, string]) =
|
||||||
let v = tab["key"] # inferred as cursor because 'tab' is not mutated.
|
let v = tab["key"] # inferred as cursor because 'tab' is not mutated.
|
||||||
# no copy into 'v', no destruction of 'v'.
|
# no copy into 'v', no destruction of 'v'.
|
||||||
use(v)
|
use(v)
|
||||||
useItAgain(v)
|
useItAgain(v)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Hook lifting
|
Hook lifting
|
||||||
|
|
@ -639,8 +628,7 @@ Hook generation
|
||||||
|
|
||||||
The ability to override a hook leads to a phase ordering problem:
|
The ability to override a hook leads to a phase ordering problem:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
type
|
type
|
||||||
Foo[T] = object
|
Foo[T] = object
|
||||||
|
|
||||||
|
|
@ -651,7 +639,7 @@ The ability to override a hook leads to a phase ordering problem:
|
||||||
|
|
||||||
proc `=destroy`[T](f: var Foo[T]) =
|
proc `=destroy`[T](f: var Foo[T]) =
|
||||||
discard
|
discard
|
||||||
|
```
|
||||||
|
|
||||||
The solution is to define ``proc `=destroy`[T](f: var Foo[T])`` before
|
The solution is to define ``proc `=destroy`[T](f: var Foo[T])`` before
|
||||||
it is used. The compiler generates implicit
|
it is used. The compiler generates implicit
|
||||||
|
|
@ -674,8 +662,7 @@ The experimental `nodestroy`:idx: pragma inhibits hook injections. This can be
|
||||||
used to specialize the object traversal in order to avoid deep recursions:
|
used to specialize the object traversal in order to avoid deep recursions:
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
|
|
||||||
type Node = ref object
|
type Node = ref object
|
||||||
x, y: int32
|
x, y: int32
|
||||||
left, right: Node
|
left, right: Node
|
||||||
|
|
@ -695,6 +682,7 @@ used to specialize the object traversal in order to avoid deep recursions:
|
||||||
# notice how even the destructor for 's' is not called implicitly
|
# notice how even the destructor for 's' is not called implicitly
|
||||||
# anymore thanks to .nodestroy, so we have to call it on our own:
|
# anymore thanks to .nodestroy, so we have to call it on our own:
|
||||||
`=destroy`(s)
|
`=destroy`(s)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
As can be seen from the example, this solution is hardly sufficient and
|
As can be seen from the example, this solution is hardly sufficient and
|
||||||
|
|
@ -712,19 +700,20 @@ The copy operation is deferred until the first write.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
var x = "abc" # no copy
|
var x = "abc" # no copy
|
||||||
var y = x # no copy
|
var y = x # no copy
|
||||||
y[0] = 'h' # copy
|
y[0] = 'h' # copy
|
||||||
|
```
|
||||||
|
|
||||||
The abstraction fails for `addr x` because whether the address is going to be used for mutations is unknown.
|
The abstraction fails for `addr x` because whether the address is going to be used for mutations is unknown.
|
||||||
`prepareMutation` needs to be called before the "address of" operation. For example:
|
`prepareMutation` needs to be called before the "address of" operation. For example:
|
||||||
|
|
||||||
.. code-block:: nim
|
```nim
|
||||||
var x = "abc"
|
var x = "abc"
|
||||||
var y = x
|
var y = x
|
||||||
|
|
||||||
prepareMutation(y)
|
prepareMutation(y)
|
||||||
moveMem(addr y[0], addr x[0], 3)
|
moveMem(addr y[0], addr x[0], 3)
|
||||||
assert y == "abc"
|
assert y == "abc"
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -1306,12 +1306,12 @@ as `MyEnum.value`:
|
||||||
|
|
||||||
OtherEnum {.pure.} = enum
|
OtherEnum {.pure.} = enum
|
||||||
valueX, valueY, valueZ, amb
|
valueX, valueY, valueZ, amb
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
echo valueA # MyEnum.valueA
|
echo valueA # MyEnum.valueA
|
||||||
echo amb # Error: Unclear whether it's MyEnum.amb or OtherEnum.amb
|
echo amb # Error: Unclear whether it's MyEnum.amb or OtherEnum.amb
|
||||||
echo MyEnum.amb # OK.
|
echo MyEnum.amb # OK.
|
||||||
|
```
|
||||||
|
|
||||||
To implement bit fields with enums see `Bit fields <#set-type-bit-fields>`_
|
To implement bit fields with enums see `Bit fields <#set-type-bit-fields>`_
|
||||||
|
|
||||||
|
|
@ -2186,7 +2186,7 @@ Unfortunately, `d + 12.Dollar` is not allowed either,
|
||||||
because `+` is defined for `int` (among others), not for `Dollar`. So
|
because `+` is defined for `int` (among others), not for `Dollar`. So
|
||||||
a `+` for dollars needs to be defined:
|
a `+` for dollars needs to be defined:
|
||||||
|
|
||||||
```
|
```nim
|
||||||
proc `+` (x, y: Dollar): Dollar =
|
proc `+` (x, y: Dollar): Dollar =
|
||||||
result = Dollar(int(x) + int(y))
|
result = Dollar(int(x) + int(y))
|
||||||
```
|
```
|
||||||
|
|
@ -2194,7 +2194,7 @@ a `+` for dollars needs to be defined:
|
||||||
It does not make sense to multiply a dollar with a dollar, but with a
|
It does not make sense to multiply a dollar with a dollar, but with a
|
||||||
number without unit; and the same holds for division:
|
number without unit; and the same holds for division:
|
||||||
|
|
||||||
```
|
```nim
|
||||||
proc `*` (x: Dollar, y: int): Dollar =
|
proc `*` (x: Dollar, y: int): Dollar =
|
||||||
result = Dollar(int(x) * y)
|
result = Dollar(int(x) * y)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue