Markdown code blocks part 3 (#20117)

No logic was added, just 4 more files migrated.
This commit is contained in:
Andrey Makarov 2022-08-04 10:32:23 +03:00 • committed by GitHub
commit a34dd3d77a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 409 additions and 283 deletions

File diff suppressed because it is too large Load diff

View file

@ -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`.

View file

@ -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.:

View file

@ -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"
```

View file

@ -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)