mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
Markdown code blocks part 3 (#20117)
No logic was added, just 4 more files migrated.
This commit is contained in:
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-
|
||||
line invocations:
|
||||
|
||||
.. code:: cmd
|
||||
|
||||
nim c hallo.nim
|
||||
nim cpp hallo.nim
|
||||
nim objc hallo.nim
|
||||
```cmd
|
||||
nim c hallo.nim
|
||||
nim cpp hallo.nim
|
||||
nim objc hallo.nim
|
||||
```
|
||||
|
||||
The compiler commands select the target backend, but if needed you can
|
||||
`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:
|
||||
(`<http://nodejs.org>`_):
|
||||
|
||||
.. code:: cmd
|
||||
|
||||
```cmd
|
||||
nim js -d:nodejs -r examples/hallo.nim
|
||||
```
|
||||
|
||||
If you experience errors saying that `globalThis` is not defined, be
|
||||
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:
|
||||
|
||||
.. code-block:: c
|
||||
```c
|
||||
int addTwoIntegers(int a, int b)
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
```
|
||||
|
||||
Create a ``calculator.nim`` file with the following content:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
{.compile: "logic.c".}
|
||||
proc addTwoIntegers(a, b: cint): cint {.importc.}
|
||||
|
||||
when isMainModule:
|
||||
echo addTwoIntegers(3, 7)
|
||||
```
|
||||
|
||||
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
|
||||
@@ -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
|
||||
typical Unix commands:
|
||||
|
||||
.. code:: cmd
|
||||
|
||||
gcc -c logic.c
|
||||
ar rvs mylib.a logic.o
|
||||
nim c --passL:mylib.a -r calculator.nim
|
||||
```cmd
|
||||
gcc -c logic.c
|
||||
ar rvs mylib.a logic.o
|
||||
nim c --passL:mylib.a -r calculator.nim
|
||||
```
|
||||
|
||||
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
|
||||
@@ -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
|
||||
from the previous section):
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc addTwoIntegers(a, b: int): int {.importc.}
|
||||
|
||||
when isMainModule:
|
||||
echo addTwoIntegers(3, 7)
|
||||
```
|
||||
|
||||
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
|
||||
@@ -253,18 +254,17 @@ Use `--nimMainPrefix:MyLib` and the function to call is named `MyLibNimMain`.
|
||||
|
||||
Create a ``fib.nim`` file with the following content:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc fib(a: cint): cint {.exportc.} =
|
||||
if a <= 2:
|
||||
result = 1
|
||||
else:
|
||||
result = fib(a - 1) + fib(a - 2)
|
||||
```
|
||||
|
||||
Create a ``maths.c`` file with the following content:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
|
||||
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));
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
program:
|
||||
|
||||
.. code:: cmd
|
||||
|
||||
```cmd
|
||||
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
|
||||
```
|
||||
|
||||
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
|
||||
@@ -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
|
||||
also ask the Nim compiler to generate a statically linked library:
|
||||
|
||||
.. code:: cmd
|
||||
|
||||
```cmd
|
||||
nim c --app:staticLib --noMain fib.nim
|
||||
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
|
||||
``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:
|
||||
|
||||
.. code-block::
|
||||
|
||||
```
|
||||
<html><body>
|
||||
<script type="text/javascript" src="fib.js"></script>
|
||||
<script type="text/javascript">
|
||||
alert("Fib for 9 is " + fib(9));
|
||||
</script>
|
||||
</body></html>
|
||||
```
|
||||
|
||||
Create a ``fib.nim`` file with the following content (or reuse the one
|
||||
from the previous section):
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc fib(a: cint): cint {.exportc.} =
|
||||
if a <= 2:
|
||||
result = 1
|
||||
else:
|
||||
result = fib(a - 1) + fib(a - 2)
|
||||
```
|
||||
|
||||
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
|
||||
@@ -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
|
||||
`cstring`. Consider the following proc:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc gimme(): cstring {.exportc.} =
|
||||
result = "Hey there C code! " & $rand(100)
|
||||
```
|
||||
|
||||
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`.
|
||||
|
||||
@@ -59,8 +59,7 @@ things like `echo "done"`. Don't use `unittest.suite` and `unittest.test`.
|
||||
|
||||
Sample test:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
block: # foo
|
||||
doAssert foo(1) == 10
|
||||
|
||||
@@ -76,6 +75,7 @@ Sample test:
|
||||
@[false, false], @[false, false]]
|
||||
# doAssert with `not` can now be done as follows:
|
||||
doAssert not (1 == 2)
|
||||
```
|
||||
|
||||
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
|
||||
@@ -110,8 +110,7 @@ For a full spec, see here: ``testament/specs.nim``
|
||||
|
||||
An example of a test:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
discard """
|
||||
errormsg: "type mismatch: got (PTest)"
|
||||
"""
|
||||
@@ -123,6 +122,7 @@ An example of a test:
|
||||
|
||||
var buf: PTest
|
||||
buf.test()
|
||||
```
|
||||
|
||||
|
||||
Running tests
|
||||
@@ -130,9 +130,9 @@ Running tests
|
||||
|
||||
You can run the tests with
|
||||
|
||||
.. code-block:: cmd
|
||||
|
||||
```cmd
|
||||
./koch tests
|
||||
```
|
||||
|
||||
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
|
||||
@@ -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
|
||||
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 megatest # runs a set of tests that can be combined into 1
|
||||
```
|
||||
|
||||
To run a single test:
|
||||
|
||||
.. code:: cmd
|
||||
|
||||
```cmd
|
||||
./koch test run <category>/<name> # e.g.: tuples/ttuples_issues
|
||||
./koch test run tests/stdlib/tos.nim # can also provide relative path
|
||||
```
|
||||
|
||||
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
|
||||
@@ -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
|
||||
the tester needs to know in order to compare the two.
|
||||
|
||||
.. code:: cmd
|
||||
|
||||
```cmd
|
||||
git checkout devel
|
||||
DEVEL_COMMIT=$(git rev-parse HEAD)
|
||||
./koch tests
|
||||
```
|
||||
|
||||
Then switch over to your changes and run the tester again.
|
||||
|
||||
.. code:: cmd
|
||||
|
||||
```cmd
|
||||
git checkout your-changes
|
||||
./koch tests
|
||||
```
|
||||
|
||||
Then you can ask the tester to create a ``testresults.html`` which will
|
||||
tell you if any new tests passed/failed.
|
||||
|
||||
.. code:: cmd
|
||||
|
||||
```cmd
|
||||
./koch tests --print html $DEVEL_COMMIT
|
||||
```
|
||||
|
||||
|
||||
Deprecation
|
||||
@@ -201,8 +201,7 @@ Deprecation
|
||||
Backward compatibility is important, so instead of a rename you need to deprecate
|
||||
the old name and introduce a new name:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
# for routines (proc/template/macro/iterator) and types:
|
||||
proc oldProc(a: int, b: float): bool {.deprecated:
|
||||
"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):
|
||||
type Bar {.deprecated.} = enum bar0, bar1
|
||||
type Barz = enum baz0, baz1 {.deprecated.}, baz2
|
||||
```
|
||||
|
||||
|
||||
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:
|
||||
as well as `testament`:cmd: and guarantee they stay in sync.
|
||||
|
||||
.. code-block:: nim
|
||||
```nim
|
||||
proc addBar*(a: string): string =
|
||||
## Adds "Bar" to `a`.
|
||||
runnableExamples:
|
||||
assert "baz".addBar == "bazBar"
|
||||
result = a & "Bar"
|
||||
```
|
||||
|
||||
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
|
||||
not guaranteed to stay in sync, so `runnableExamples` is almost always preferred:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
````nim
|
||||
proc someProc*(): string =
|
||||
## Returns "something"
|
||||
##
|
||||
## .. code-block::
|
||||
## echo someProc() # "something"
|
||||
## ```
|
||||
## echo someProc() # "something"
|
||||
## ```
|
||||
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
|
||||
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
|
||||
first appearance of the proc.
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc hello*(): string
|
||||
## Put documentation here
|
||||
proc nothing() = discard
|
||||
proc hello*(): string =
|
||||
## ignore this
|
||||
echo "hello"
|
||||
```
|
||||
|
||||
The preferred documentation style is to begin with a capital letter and use
|
||||
the third-person singular. That is, between:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc hello*(): string =
|
||||
## Returns "hello"
|
||||
result = "hello"
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc hello*(): string =
|
||||
## say hello
|
||||
result = "hello"
|
||||
```
|
||||
|
||||
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
|
||||
example below) from `Nim Index`_ can be used in doc comment this way:
|
||||
|
||||
.. code-block:: nim
|
||||
```nim
|
||||
## A higher level `SQLite`:idx: database wrapper.
|
||||
```
|
||||
|
||||
.. _`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
|
||||
to avoid name conflicts across packages.
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
# if in nim sources
|
||||
when defined(allocStats): discard # bad, can cause conflicts
|
||||
when defined(nimAllocStats): discard # preferred
|
||||
# if in a package `cligen`:
|
||||
when defined(debug): discard # bad, can cause conflicts
|
||||
when defined(cligenDebug): discard # preferred
|
||||
```
|
||||
|
||||
.. _noimplicitbool:
|
||||
Take advantage of no implicit bool conversion
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
doAssert isValid() == true
|
||||
doAssert isValid() # preferred
|
||||
```
|
||||
|
||||
.. _design_for_mcs:
|
||||
Design with method call syntax chaining in mind
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc foo(cond: bool, lines: seq[string]) # bad
|
||||
proc foo(lines: seq[string], cond: bool) # preferred
|
||||
# can be called as: `getLines().foo(false)`
|
||||
```
|
||||
|
||||
.. _avoid_quit:
|
||||
Use exceptions (including `assert` / `doAssert`) instead of `quit`
|
||||
rationale: https://forum.nim-lang.org/t/4089
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
quit() # bad in almost all cases
|
||||
doAssert() # preferred
|
||||
```
|
||||
|
||||
.. _tests_use_doAssert:
|
||||
Use `doAssert` (or `unittest.check`, `unittest.require`), not `assert` in all
|
||||
tests so they'll be enabled even with `--assertions:off`:option:.
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
block: # foo
|
||||
assert foo() # bad
|
||||
doAssert foo() # preferred
|
||||
```
|
||||
|
||||
.. _runnableExamples_use_assert:
|
||||
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
|
||||
second example below:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
runnableExamples:
|
||||
doAssert foo() # bad
|
||||
assert foo() # preferred
|
||||
|
||||
runnableExamples("-d:danger"):
|
||||
doAssert foo() # `assert` would be disabled here, so `doAssert` makes more sense
|
||||
```
|
||||
|
||||
.. _delegate_printing:
|
||||
Delegate printing to caller: return `string` instead of calling `echo`
|
||||
rationale: it's more flexible (e.g. allows the caller to call custom printing,
|
||||
including prepending location info, writing to log files, etc).
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc foo() = echo "bar" # bad
|
||||
proc foo(): string = "bar" # preferred (usually)
|
||||
```
|
||||
|
||||
.. _use_Option:
|
||||
[Ongoing debate] Consider using Option instead of return bool + var argument,
|
||||
unless stack allocation is needed (e.g. for efficiency).
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc foo(a: var Bar): bool
|
||||
proc foo(): Option[Bar]
|
||||
```
|
||||
|
||||
.. _use_doAssert_not_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
|
||||
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`.
|
||||
doAssert foo() == [1, 2] # preferred, except when not possible to do so.
|
||||
```
|
||||
|
||||
|
||||
The `git`:cmd: stuff
|
||||
@@ -480,10 +484,10 @@ General commit rules
|
||||
Always check your changes for whitespace errors using `git diff --check`:cmd:
|
||||
or add the following ``pre-commit`` hook:
|
||||
|
||||
.. code:: cmd
|
||||
|
||||
#!/bin/sh
|
||||
git diff --check --cached || exit $?
|
||||
```cmd
|
||||
#!/bin/sh
|
||||
git diff --check --cached || exit $?
|
||||
```
|
||||
5. Describe your commit and use your common sense.
|
||||
Example commit message::
|
||||
|
||||
@@ -565,10 +569,10 @@ Code reviews
|
||||
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>`_:
|
||||
|
||||
.. code:: cmd
|
||||
|
||||
git fetch origin pull/10431/head && git checkout FETCH_HEAD
|
||||
git diff --color-moved-ws=allow-indentation-change --color-moved=blocks HEAD^
|
||||
```cmd
|
||||
git fetch origin pull/10431/head && git checkout FETCH_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
|
||||
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
|
||||
written as:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
type
|
||||
myseq*[T] = object
|
||||
len, cap: int
|
||||
@@ -91,7 +90,7 @@ written as:
|
||||
for i in 0..<result.len: result.data[i] = elems[i]
|
||||
|
||||
proc len*[T](x: myseq[T]): int {.inline.} = x.len
|
||||
|
||||
```
|
||||
|
||||
|
||||
Lifetime-tracking hooks
|
||||
@@ -119,20 +118,18 @@ to return.
|
||||
|
||||
The prototype of this hook for a type `T` needs to be:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc `=destroy`(x: var T)
|
||||
|
||||
```
|
||||
|
||||
The general pattern in `=destroy` looks like:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc `=destroy`(x: var T) =
|
||||
# first check if 'x' was moved to somewhere else:
|
||||
if x.field != nil:
|
||||
freeResource(x.field)
|
||||
|
||||
```
|
||||
|
||||
|
||||
`=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:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc `=sink`(dest: var T; source: T)
|
||||
|
||||
```
|
||||
|
||||
The general pattern in `=sink` looks like:
|
||||
|
||||
.. code-block:: nim
|
||||
```nim
|
||||
|
||||
proc `=sink`(dest: var T; source: T) =
|
||||
`=destroy`(dest)
|
||||
wasMoved(dest)
|
||||
dest.field = source.field
|
||||
|
||||
```
|
||||
|
||||
**Note**: `=sink` does not need to check for self-assignments.
|
||||
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:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc `=copy`(dest: var T; source: T)
|
||||
|
||||
```
|
||||
|
||||
The general pattern in `=copy` looks like:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc `=copy`(dest: var T; source: T) =
|
||||
# protect against self-assignments:
|
||||
if dest.field != source.field:
|
||||
`=destroy`(dest)
|
||||
wasMoved(dest)
|
||||
dest.field = duplicateResource(source.field)
|
||||
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc `=copy`(dest: var T; source: T) {.error.}
|
||||
```
|
||||
|
||||
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.
|
||||
@@ -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:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc `=trace`(dest: var T; env: pointer)
|
||||
```
|
||||
|
||||
`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.
|
||||
@@ -233,8 +227,7 @@ prevent the automatic creation.
|
||||
|
||||
The general pattern in using `=destroy` with `=trace` looks like:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
type
|
||||
Test[T] = object
|
||||
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)
|
||||
|
||||
# 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
|
||||
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;
|
||||
however, object and tuple fields are treated as separate entities:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc consume(x: sink Obj) = discard "no implementation"
|
||||
|
||||
proc main =
|
||||
@@ -316,16 +309,16 @@ however, object and tuple fields are treated as separate entities:
|
||||
consume tup[0]
|
||||
# ok, only tup[0] was consumed, tup[1] is still alive:
|
||||
echo tup[1]
|
||||
|
||||
```
|
||||
|
||||
Sometimes it is required to explicitly `move` a value into its final position:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc main =
|
||||
var dest, src: array[10, string]
|
||||
# ...
|
||||
for i in 0..high(dest): dest[i] = move(src[i])
|
||||
```
|
||||
|
||||
An implementation is allowed, but not required to implement even more move
|
||||
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
|
||||
for a single routine:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc addX(x: T; child: T) {.nosinks.} =
|
||||
x.s.add child
|
||||
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc select(cond: bool; a, b: sink string): string =
|
||||
if cond:
|
||||
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"
|
||||
# possible self-assignment:
|
||||
x = select(true, x, y)
|
||||
|
||||
```
|
||||
|
||||
Is transformed into:
|
||||
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc select(cond: bool; a, b: sink string): string =
|
||||
try:
|
||||
if cond:
|
||||
@@ -506,6 +495,7 @@ Is transformed into:
|
||||
finally:
|
||||
`=destroy`(y)
|
||||
`=destroy`(x)
|
||||
```
|
||||
|
||||
As can be manually verified, this transformation is correct for
|
||||
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`.
|
||||
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
type
|
||||
Tree = object
|
||||
kids: seq[Tree]
|
||||
@@ -553,6 +542,7 @@ for expressions of type `lent T` or of type `var T`.
|
||||
# everything turned into moves:
|
||||
let t = construct(@[construct(@[]), construct(@[])])
|
||||
echo t[0] # accessor does not copy the element!
|
||||
```
|
||||
|
||||
|
||||
The cursor pragma
|
||||
@@ -564,12 +554,12 @@ This means that cyclic structures cannot be freed
|
||||
immediately (`--mm:orc`:option: ships with a cycle collector).
|
||||
With the `cursor` pragma one can break up cycles declaratively:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
type
|
||||
Node = ref object
|
||||
left: Node # 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
|
||||
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
|
||||
to avoid this overhead:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
var it {.cursor.} = listRoot
|
||||
while it != nil:
|
||||
use(it)
|
||||
it = it.next
|
||||
|
||||
```
|
||||
|
||||
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
|
||||
@@ -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
|
||||
indirections:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
proc main(tab: Table[string, string]) =
|
||||
let v = tab["key"] # inferred as cursor because 'tab' is not mutated.
|
||||
# no copy into 'v', no destruction of 'v'.
|
||||
use(v)
|
||||
useItAgain(v)
|
||||
```
|
||||
|
||||
|
||||
Hook lifting
|
||||
@@ -639,8 +628,7 @@ Hook generation
|
||||
|
||||
The ability to override a hook leads to a phase ordering problem:
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
type
|
||||
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]) =
|
||||
discard
|
||||
|
||||
```
|
||||
|
||||
The solution is to define ``proc `=destroy`[T](f: var Foo[T])`` before
|
||||
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:
|
||||
|
||||
|
||||
.. code-block:: nim
|
||||
|
||||
```nim
|
||||
type Node = ref object
|
||||
x, y: int32
|
||||
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
|
||||
# anymore thanks to .nodestroy, so we have to call it on our own:
|
||||
`=destroy`(s)
|
||||
```
|
||||
|
||||
|
||||
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:
|
||||
|
||||
.. code-block:: nim
|
||||
```nim
|
||||
var x = "abc" # no copy
|
||||
var y = x # no copy
|
||||
y[0] = 'h' # copy
|
||||
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
.. code-block:: nim
|
||||
```nim
|
||||
var x = "abc"
|
||||
var y = x
|
||||
|
||||
prepareMutation(y)
|
||||
moveMem(addr y[0], addr x[0], 3)
|
||||
assert y == "abc"
|
||||
```
|
||||
|
||||
@@ -1306,12 +1306,12 @@ as `MyEnum.value`:
|
||||
|
||||
OtherEnum {.pure.} = enum
|
||||
valueX, valueY, valueZ, amb
|
||||
```
|
||||
|
||||
|
||||
echo valueA # MyEnum.valueA
|
||||
echo amb # Error: Unclear whether it's MyEnum.amb or OtherEnum.amb
|
||||
echo MyEnum.amb # OK.
|
||||
```
|
||||
|
||||
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
|
||||
a `+` for dollars needs to be defined:
|
||||
|
||||
```
|
||||
```nim
|
||||
proc `+` (x, y: Dollar): Dollar =
|
||||
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
|
||||
number without unit; and the same holds for division:
|
||||
|
||||
```
|
||||
```nim
|
||||
proc `*` (x: Dollar, y: int): Dollar =
|
||||
result = Dollar(int(x) * y)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user