Markdown code blocks part 4 (#20189)

No logic was added, just 8 more files have been migrated.
This commit is contained in:
Andrey Makarov
2022-08-12 21:33:43 +03:00
committed by GitHub
parent 8155837cde
commit 713f39083e
9 changed files with 365 additions and 341 deletions

View File

@@ -18,11 +18,11 @@ General Guidelines
* (debatable) In nim sources, for links, prefer ``[link text](link.html)`` to `\`link text<link.html>\`_`:code:
since the syntax is simpler and markdown is more common (likewise, `nim rst2html`:cmd: also supports it in ``rst`` files).
.. code-block:: nim
```nim
proc someproc*(s: string, foo: int) =
## Use single backticks for inline code, e.g.: `s` or `someExpr(true)`.
## Use a backlash to follow with alphanumeric char: `int8`\s are great.
```
Module-level documentation
@@ -32,23 +32,24 @@ Documentation of a module is placed at the top of the module itself. Each line o
Sometimes `##[ multiline docs containing code ]##` is preferable, see ``lib/pure/times.nim``.
Code samples are encouraged, and should follow the general RST syntax:
.. code-block:: Nim
````Nim
## The `universe` module computes the answer to life, the universe, and everything.
##
## .. code-block::
## doAssert computeAnswerString() == 42
## ```
## doAssert computeAnswerString() == 42
## ```
````
Within this top-level comment, you can indicate the authorship and copyright of the code, which will be featured in the produced documentation.
.. code-block:: Nim
```Nim
## This is the best module ever. It provides answers to everything!
##
## :Author: Steve McQueen
## :Copyright: 1965
##
```
Leave a space between the last line of top-level documentation and the beginning of Nim code (the imports, etc.).
@@ -57,28 +58,29 @@ Procs, Templates, Macros, Converters, and Iterators
The documentation of a procedure should begin with a capital letter and should be in present tense. Variables referenced in the documentation should be surrounded by single tick marks:
.. code-block:: Nim
```Nim
proc example1*(x: int) =
## Prints the value of `x`.
echo x
```
Whenever an example of usage would be helpful to the user, you should include one within the documentation in RST format as below.
.. code-block:: Nim
````Nim
proc addThree*(x, y, z: int8): int =
## Adds three `int8` values, treating them as unsigned and
## truncating the result.
##
## .. code-block::
## # things that aren't suitable for a `runnableExamples` go in code-block:
## echo execCmdEx("git pull")
## drawOnScreen()
## ```
## # things that aren't suitable for a `runnableExamples` go in code-block:
## echo execCmdEx("git pull")
## drawOnScreen()
## ```
runnableExamples:
# `runnableExamples` is usually preferred to ``code-block``, when possible.
doAssert addThree(3, 125, 6) == -122
result = x +% y +% z
````
The command `nim doc`:cmd: will then correctly syntax highlight the Nim code within the documentation.
@@ -87,8 +89,7 @@ Types
Exported types should also be documented. This documentation can also contain code samples, but those are better placed with the functions to which they refer.
.. code-block:: Nim
```Nim
type
NamedQueue*[T] = object ## Provides a linked data structure with names
## throughout. It is named for convenience. I'm making
@@ -96,12 +97,12 @@ Exported types should also be documented. This documentation can also contain co
name*: string ## The name of the item
val*: T ## Its value
next*: ref NamedQueue[T] ## The next item in the queue
```
You have some flexibility when placing the documentation:
.. code-block:: Nim
```Nim
type
NamedQueue*[T] = object
## Provides a linked data structure with names
@@ -110,11 +111,11 @@ You have some flexibility when placing the documentation:
name*: string ## The name of the item
val*: T ## Its value
next*: ref NamedQueue[T] ## The next item in the queue
```
Make sure to place the documentation beside or within the object.
.. code-block:: Nim
```Nim
type
## Bad: this documentation disappears because it annotates the `type` keyword
## above, not `NamedQueue`.
@@ -123,14 +124,14 @@ Make sure to place the documentation beside or within the object.
## is not what we want.
val*: T ## Its value
next*: ref NamedQueue[T] ## The next item in the queue
```
Var, Let, and Const
-------------------
When declaring module-wide constants and values, documentation is encouraged. The placement of doc comments is similar to the `type` sections.
.. code-block:: Nim
```Nim
const
X* = 42 ## An awesome number.
SpreadArray* = [
@@ -138,25 +139,26 @@ When declaring module-wide constants and values, documentation is encouraged. Th
[2,3,1],
[3,1,2],
] ## Doc comment for `SpreadArray`.
```
Placement of comments in other areas is usually allowed, but will not become part of the documentation output and should therefore be prefaced by a single hash (`#`).
.. code-block:: Nim
```Nim
const
BadMathVals* = [
3.14, # pi
2.72, # e
0.58, # gamma
] ## A bunch of badly rounded values.
```
Nim supports Unicode in comments, so the above can be replaced with the following:
.. code-block:: Nim
```Nim
const
BadMathVals* = [
3.14, # π
2.72, # e
0.58, # γ
] ## A bunch of badly rounded values (including π!).
```

View File

@@ -22,11 +22,11 @@ DrNim's command-line options are the same as the Nim compiler's.
DrNim currently only checks the sections of your code that are marked
via `staticBoundChecks: on`:
.. code-block:: nim
```nim
{.push staticBoundChecks: on.}
# <--- code section here ---->
{.pop.}
```
DrNim currently only tries to prove array indexing or subrange checks,
overflow errors are *not* prevented. Overflows will be checked for in
@@ -53,8 +53,7 @@ Motivating Example
The follow example highlights what DrNim can easily do, even
without additional annotations:
.. code-block:: nim
```nim
{.push staticBoundChecks: on.}
proc sum(a: openArray[int]): int =
@@ -64,6 +63,7 @@ without additional annotations:
{.pop.}
echo sum([1, 2, 3])
```
This program contains a famous "index out of bounds" bug. DrNim
detects it and produces the following error message::
@@ -125,8 +125,7 @@ Example: insertionSort
**Note**: This example does not yet work with DrNim.
.. code-block:: nim
```nim
import std / logic
proc insertionSort(a: var openArray[int]) {.
@@ -142,6 +141,7 @@ Example: insertionSort
{.invariant: forall(j in 1..k, i in 0..<j, j == t or a[i] <= a[j]).}
swap a[t], a[t-1]
dec t
```
Unfortunately, the invariants required to prove that this code is correct take more
code than the imperative instructions. However, this effort can be compensated
@@ -155,14 +155,14 @@ This is required, but not sufficient to describe that a `sort` operation
was performed. For example, the same postcondition is true for this proc
which doesn't sort at all:
.. code-block:: nim
```nim
import std / logic
proc insertionSort(a: var openArray[int]) {.
ensures: forall(i in 1..<a.len, a[i-1] <= a[i]).} =
# does not sort, overwrites `a`'s contents!
for i in 0..<a.len: a[i] = i
```

View File

@@ -13,11 +13,12 @@ difficult is the ``newString`` proc: If it is simply wrapped, it
should not be evaluated at compile time! On other occasions it can
and should be evaluated:
.. code-block:: nim
```nim
proc toUpper(s: string): string =
result = newString(len(s))
for i in 0..len(s) - 1:
result[i] = toUpper(s[i])
```
No, it really can always be evaluated. The code generator should transform
``s = "\0\0\0..."`` back into ``s = newString(...)``.

View File

@@ -41,10 +41,11 @@ recognize it as Nim source file).
If we use `generateXML` code shown above and call the SCF file `xmlGen.nimf`
In your `main.nim`:
.. code-block:: nim
```nim
include "xmlGen.nimf"
echo generateXML("John Smith","42")
```
Pipe operator
=============
@@ -150,7 +151,7 @@ Example::
The filter transforms this into:
.. code-block:: nim
```nim
proc generateHTMLPage(title, currentTab, content: string,
tabs: openArray[string]): string =
result = ""
@@ -173,6 +174,7 @@ The filter transforms this into:
" A dollar: $.\n" &
" </div>\n" &
"</body>\n")
```
Each line that does not start with the meta character (ignoring leading

View File

@@ -26,8 +26,7 @@ code when `F9` is pressed. The important lines are marked with `#***`.
To install SDL2 you can use `nimble install sdl2`:cmd:.
.. code-block:: nim
```nim
# logic.nim
import sdl2
@@ -83,10 +82,10 @@ To install SDL2 you can use `nimble install sdl2`:cmd:.
discard renderer.fillRect(rect)
delay(16)
renderer.present()
```
.. code-block:: nim
```nim
# mymain.nim
import logic
@@ -97,42 +96,44 @@ To install SDL2 you can use `nimble install sdl2`:cmd:.
destroy()
main()
```
Compile this example via:
```cmd
```cmd
nim c --hotcodereloading:on mymain.nim
```
```
Now start the program and KEEP it running!
.. code:: cmd
```cmd
# Unix:
mymain &
# or Windows (click on the .exe)
mymain.exe
# edit
```
For example, change the line:
```nim
```nim
discard renderer.setDrawColor(255, 128, 128, 0)
```
```
into:
```nim
```nim
discard renderer.setDrawColor(255, 255, 128, 0)
```
```
(This will change the color of the rectangle.)
Then recompile the project, but do not restart or quit the mymain.exe program!
```cmd
```cmd
nim c --hotcodereloading:on mymain.nim
```
```
Now give the `mymain` SDL window the focus, press F9, and watch the
updated version of the program.
@@ -146,7 +147,7 @@ One can use the special event handlers `beforeCodeReload` and
`afterCodeReload` to reset the state of a particular variable or to force
the execution of certain statements:
.. code-block:: Nim
```Nim
var
settings = initTable[string, string]()
lastReload: Time
@@ -159,6 +160,7 @@ the execution of certain statements:
afterCodeReload:
lastReload = now()
resetProgramState()
```
On each code reload, Nim will first execute all `beforeCodeReload`:idx:
handlers registered in the previous version of the program and then all
@@ -167,7 +169,7 @@ that any handlers appearing in modules that weren't reloaded will also be
executed. To prevent this behavior, one can guard the code with the
`hasModuleChanged()`:idx: API:
.. code-block:: Nim
```Nim
import mydb
var myCache = initTable[Key, Value]()
@@ -175,6 +177,7 @@ executed. To prevent this behavior, one can guard the code with the
afterCodeReload:
if hasModuleChanged(mydb):
resetCache(myCache)
```
The hot code reloading is based on dynamic library hot swapping in the native
targets and direct manipulation of the global namespace in the JavaScript
@@ -203,8 +206,7 @@ runtime demands of the example code above. An example of compiling
``nimhcr.nim`` and ``nimrtl.nim`` when the source dir of Nim is installed
with choosenim follows.
.. code:: console
```console
# Unix/MacOS
# Make sure you are in the directory containing your .nim files
$ cd your-source-directory
@@ -215,6 +217,7 @@ with choosenim follows.
# verify that you have two files named libnimhcr and libnimrtl in your
# source directory (.dll for Windows, .so for Unix, .dylib for MacOS)
```
All modules of the project will be compiled to separate dynamic link
libraries placed in the `nimcache` directory. Please note that during

View File

@@ -10,10 +10,7 @@
.. contents::
.. raw:: html
<blockquote><p>
"yes, I'm the creator" -- Araq, 2013-07-26 19:28:32.
</p></blockquote>
> "yes, I'm the creator" -- Araq, 2013-07-26 19:28:32.
Note: this is mostly outdated, see instead `nimsuggest <nimsuggest.html>`_
@@ -246,11 +243,12 @@ skConst
| **Fourth column**: the type of the const value.
| **Docstring**: always the empty string.
.. code-block:: nim
const SOME_SEQUENCE = @[1, 2]
--> col 2: $MODULE.SOME_SEQUENCE
col 3: seq[int]
col 7: ""
```nim
const SOME_SEQUENCE = @[1, 2]
--> col 2: $MODULE.SOME_SEQUENCE
col 3: seq[int]
col 7: ""
```
skEnumField
@@ -260,11 +258,12 @@ skEnumField
| **Fourth column**: enum type grouping other enum fields.
| **Docstring**: always the empty string.
.. code-block:: nim
Open(filename, fmWrite)
--> col 2: system.FileMode.fmWrite
col 3: FileMode
col 7: ""
```nim
Open(filename, fmWrite)
--> col 2: system.FileMode.fmWrite
col 3: FileMode
col 7: ""
```
skForVar
@@ -274,13 +273,14 @@ skForVar
| **Fourth column**: type of the var.
| **Docstring**: always the empty string.
.. code-block:: nim
proc looper(filename = "tests.nim") =
for letter in filename:
echo letter
--> col 2: $MODULE.looper.letter
col 3: char
col 7: ""
```nim
proc looper(filename = "tests.nim") =
for letter in filename:
echo letter
--> col 2: $MODULE.looper.letter
col 3: char
col 7: ""
```
skIterator, skClosureIterator
@@ -295,13 +295,14 @@ posterior instances of the iterator.
| **Fourth column**: signature of the iterator including return type.
| **Docstring**: docstring if available.
.. code-block:: nim
let
text = "some text"
letters = toSeq(runes(text))
--> col 2: unicode.runes
col 3: iterator (string): Rune
col 7: "iterates over any unicode character of the string `s`."
```nim
let
text = "some text"
letters = toSeq(runes(text))
--> col 2: unicode.runes
col 3: iterator (string): Rune
col 7: "iterates over any unicode character of the string `s`."
```
skLabel
@@ -311,13 +312,14 @@ skLabel
| **Fourth column**: always the empty string.
| **Docstring**: always the empty string.
.. code-block:: nim
proc test(text: string) =
var found = -1
block loops:
--> col 2: $MODULE.test.loops
col 3: ""
col 7: ""
```nim
proc test(text: string) =
var found = -1
block loops:
--> col 2: $MODULE.test.loops
col 3: ""
col 7: ""
```
skLet
@@ -327,12 +329,13 @@ skLet
| **Fourth column**: the type of the let variable.
| **Docstring**: always the empty string.
.. code-block:: nim
let
text = "some text"
--> col 2: $MODULE.text
col 3: string
col 7: ""
```nim
let
text = "some text"
--> col 2: $MODULE.text
col 3: string
col 7: ""
```
skMacro
@@ -347,12 +350,13 @@ posterior instances of the macro.
| **Fourth column**: signature of the macro including return type.
| **Docstring**: docstring if available.
.. code-block:: nim
proc testMacro() =
expect(EArithmetic):
--> col 2: idetools_api.expect
col 3: proc (varargs[expr], stmt): stmt
col 7: ""
```nim
proc testMacro() =
expect(EArithmetic):
--> col 2: idetools_api.expect
col 3: proc (varargs[expr], stmt): stmt
col 7: ""
```
skMethod
@@ -384,14 +388,15 @@ This may change in the future.
| **Fourth column**: signature of the method including return type.
| **Docstring**: docstring if available.
.. code-block:: nim
method eval(e: PExpr): int = quit "to override!"
method eval(e: PLiteral): int = e.x
method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b)
echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
--> col 2: $MODULE.eval
col 3: proc (PPlusExpr): int
col 7: ""
```nim
method eval(e: PExpr): int = quit "to override!"
method eval(e: PLiteral): int = e.x
method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b)
echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))
--> col 2: $MODULE.eval
col 3: proc (PPlusExpr): int
col 7: ""
```
skParam
@@ -401,12 +406,13 @@ skParam
| **Fourth column**: the type of the parameter.
| **Docstring**: always the empty string.
.. code-block:: nim
proc reader(filename = "tests.nim") =
let text = readFile(filename)
--> col 2: $MODULE.reader.filename
col 3: string
col 7: ""
```nim
proc reader(filename = "tests.nim") =
let text = readFile(filename)
--> col 2: $MODULE.reader.filename
col 3: string
col 7: ""
```
skProc
@@ -425,15 +431,16 @@ returned by idetools returns also the pragmas for the proc.
| **Fourth column**: signature of the proc including return type.
| **Docstring**: docstring if available.
.. code-block:: nim
open(filename, fmWrite)
--> col 2: system.Open
col 3: proc (var File, string, FileMode, int): bool
col 7:
"Opens a file named `filename` with given `mode`.
```nim
open(filename, fmWrite)
--> col 2: system.Open
col 3: proc (var File, string, FileMode, int): bool
col 7:
"Opens a file named `filename` with given `mode`.
Default mode is readonly. Returns true iff the file could be opened.
This throws no exception if the file could not be opened."
Default mode is readonly. Returns true iff the file could be opened.
This throws no exception if the file could not be opened."
```
skResult
@@ -443,12 +450,13 @@ skResult
| **Fourth column**: the type of the result.
| **Docstring**: always the empty string.
.. code-block:: nim
proc getRandomValue() : int =
return 4
--> col 2: $MODULE.getRandomValue.result
col 3: int
col 7: ""
```nim
proc getRandomValue() : int =
return 4
--> col 2: $MODULE.getRandomValue.result
col 3: int
col 7: ""
```
skTemplate
@@ -463,7 +471,7 @@ posterior instances of the template.
| **Fourth column**: signature of the template including return type.
| **Docstring**: docstring if available.
.. code-block:: nim
`````nim
let
text = "some text"
letters = toSeq(runes(text))
@@ -474,13 +482,15 @@ posterior instances of the template.
Example:
.. code-block:: nim
```nim
let
numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
if x mod 2 == 1:
result = true)
assert odd_numbers == @[1, 3, 5, 7, 9]"
```
`````
skType
@@ -490,12 +500,13 @@ skType
| **Fourth column**: the type.
| **Docstring**: always the empty string.
.. code-block:: nim
proc writeTempFile() =
var output: File
--> col 2: system.File
col 3: File
col 7: ""
```nim
proc writeTempFile() =
var output: File
--> col 2: system.File
col 3: File
col 7: ""
```
skVar
@@ -505,14 +516,15 @@ skVar
| **Fourth column**: the type of the var.
| **Docstring**: always the empty string.
.. code-block:: nim
proc writeTempFile() =
var output: File
output.open("/tmp/somefile", fmWrite)
output.write("test")
--> col 2: $MODULE.writeTempFile.output
col 3: File
col 7: ""
```nim
proc writeTempFile() =
var output: File
output.open("/tmp/somefile", fmWrite)
output.write("test")
--> col 2: $MODULE.writeTempFile.output
col 3: File
col 7: ""
```
Test suite

View File

@@ -42,25 +42,25 @@ Bootstrapping the compiler
Compiling the compiler is a simple matter of running:
.. code:: cmd
```cmd
nim c koch.nim
koch boot -d:release
```
For a debug version use:
.. code:: cmd
```cmd
nim c koch.nim
koch boot
```
And for a debug version compatible with GDB:
.. code:: cmd
```cmd
nim c koch.nim
koch boot --debuginfo --linedir:on
```
The `koch`:cmd: program is Nim's maintenance script. It is a replacement for
make and shell scripting with the advantage that it is much more portable.
@@ -73,10 +73,10 @@ Reproducible builds
Set the compilation timestamp with the `SOURCE_DATE_EPOCH` environment variable.
.. code:: cmd
```cmd
export SOURCE_DATE_EPOCH=$(git log -n 1 --format=%at)
koch boot # or `./build_all.sh`
```
Debugging the compiler
@@ -98,10 +98,10 @@ focus on the changes introduced by that one specific commit.
compilation fails. This exit code tells `git bisect`:cmd: to skip the
current commit:
.. code:: cmd
```cmd
git bisect start bad-commit good-commit
git bisect run ./koch temp -r c test-source.nim
```
You can also bisect using custom options to build the compiler, for example if
you don't need a debug version of the compiler (which runs slower), you can replace
@@ -141,8 +141,7 @@ enabled. Here are compiler options that are of interest when debugging:
Another method to build and run the compiler is directly through `koch`:cmd:\:
.. code:: cmd
```cmd
koch temp [options] c test.nim
# (will build with js support)
@@ -150,6 +149,7 @@ Another method to build and run the compiler is directly through `koch`:cmd:\:
# (will build with doc support)
koch temp [options] doc test.nim
```
Debug logging
-------------
@@ -166,17 +166,16 @@ is being used. One very common way to achieve this is to use the `mdbg` conditio
which will be true only in contexts, processing expressions and statements from
the currently compiled main module:
.. code-block:: nim
```nim
# inside some compiler module
if mdbg:
debug someAstNode
```
Using the `isCompilerDebug`:nim: condition along with inserting some statements
into the testcase provides more granular logging:
.. code-block:: nim
```nim
# compilermodule.nim
if isCompilerDebug():
debug someAstNode
@@ -186,21 +185,21 @@ into the testcase provides more granular logging:
{.define(nimCompilerDebug).}
let a = 2.5 * 3
{.undef(nimCompilerDebug).}
```
Logging can also be scoped to a specific filename as well. This will of course
match against every module with that name.
.. code-block:: nim
```nim
if `??`(conf, n.info, "module.nim"):
debug(n)
```
The above examples also makes use of the `debug`:nim: proc, which is able to
print a human-readable form of an arbitrary AST tree. Other common ways to print
information about the internal compiler types include:
.. code-block:: nim
```nim
# pretty print PNode
# pretty prints the Nim ast
@@ -246,23 +245,24 @@ information about the internal compiler types include:
# print the structure of any type
repr(someVar)
```
Here are some other helpful utilities:
.. code-block:: nim
```nim
# how did execution reach this location?
writeStackTrace()
```
These procs may not already be imported by the module you're editing.
You can import them directly for debugging:
.. code-block:: nim
```nim
from astalgo import debug
from types import typeToString
from renderer import renderTree
from msgs import `??`
```
Native debugging
----------------
@@ -280,12 +280,12 @@ and `exitingDebugSection()`:nim:.
* LLDB execute `command source tools/compiler.lldb` at startup
#. Use one of the scoping helpers like so:
.. code-block:: nim
```nim
if isCompilerDebug():
enteringDebugSection()
else:
exitingDebugSection()
```
A caveat of this method is that all breakpoints and watchpoints are enabled or
disabled. Also, due to a bug, only breakpoints can be constrained for LLDB.
@@ -448,8 +448,9 @@ Tests with GCC on Amd64 showed that it's really beneficial if the
Proper thunk generation is harder because the proc that is to wrap
could stem from a complex expression:
.. code-block:: nim
```nim
receivesClosure(returnsDefaultCC[i])
```
A thunk would need to call 'returnsDefaultCC[i]' somehow and that would require
an *additional* closure generation... Ok, not really, but it requires to pass
@@ -460,17 +461,18 @@ to pass a proc pointer around via a generic `ref` type.
Example code:
.. code-block:: nim
```nim
proc add(x: int): proc (y: int): int {.closure.} =
return proc (y: int): int =
return x + y
var add2 = add(2)
echo add2(5) #OUT 7
```
This should produce roughly this code:
.. code-block:: nim
```nim
type
Env = ref object
x: int # data
@@ -487,11 +489,12 @@ This should produce roughly this code:
var add2 = add(2)
let tmp = if add2.data == nil: add2.prc(5) else: add2.prc(5, add2.data)
echo tmp
```
Beware of nesting:
.. code-block:: nim
```nim
proc add(x: int): proc (y: int): proc (z: int): int {.closure.} {.closure.} =
return lambda (y: int): proc (z: int): int {.closure.} =
return lambda (z: int): int =
@@ -499,10 +502,11 @@ Beware of nesting:
var add24 = add(2)(4)
echo add24(5) #OUT 11
```
This should produce roughly this code:
.. code-block:: nim
```nim
type
EnvX = ref object
x: int # data
@@ -530,6 +534,7 @@ This should produce roughly this code:
var tmp2 = tmp.fn(4, tmp.data)
var add24 = tmp2.fn(4, tmp2.data)
echo add24(5)
```
We could get rid of nesting environments by always inlining inner anon procs.
@@ -540,8 +545,7 @@ however.
Accumulator
-----------
.. code-block:: nim
```nim
proc getAccumulator(start: int): proc (): int {.closure} =
var i = start
return lambda: int =
@@ -560,6 +564,7 @@ Accumulator
var a = accumulator(3)
var b = accumulator(4)
echo a() + b()
```
Internals
@@ -614,36 +619,36 @@ keeps the full `int literal(321)` type. Here is an example where that
difference matters.
.. code-block:: nim
```nim
proc foo(arg: int8) =
echo "def"
proc foo(arg: int8) =
echo "def"
const tmp1 = 123
foo(tmp1) # OK
const tmp1 = 123
foo(tmp1) # OK
let tmp2 = 123
foo(tmp2) # Error
let tmp2 = 123
foo(tmp2) # Error
```
In a context with multiple overloads, the integer literal kind will
always prefer the `int` type over all other types. If none of the
overloads is of type `int`, then there will be an error because of
ambiguity.
.. code-block:: nim
```nim
proc foo(arg: int) =
echo "abc"
proc foo(arg: int8) =
echo "def"
foo(123) # output: abc
proc foo(arg: int) =
echo "abc"
proc foo(arg: int8) =
echo "def"
foo(123) # output: abc
proc bar(arg: int16) =
echo "abc"
proc bar(arg: int8) =
echo "def"
proc bar(arg: int16) =
echo "abc"
proc bar(arg: int8) =
echo "def"
bar(123) # Error ambiguous call
bar(123) # Error ambiguous call
```
In the compiler these integer literal types are represented with the
node kind `nkIntLit`, type kind `tyInt` and the member `n` of the type

View File

@@ -8,10 +8,7 @@
.. include:: rstcommon.rst
.. contents::
.. raw:: html
<blockquote><p>
"A great chef is an artist that I truly respect" -- Robert Stack.
</p></blockquote>
> "A great chef is an artist that I truly respect" -- Robert Stack.
Introduction

View File

@@ -30,17 +30,16 @@ The `void` type denotes the absence of any type. Parameters of
type `void` are treated as non-existent, `void` as a return type means that
the procedure does not return a value:
.. code-block:: nim
```nim
proc nothing(x, y: void): void =
echo "ha"
nothing() # writes "ha" to stdout
```
The `void` type is particularly useful for generic code:
.. code-block:: nim
```nim
proc callProc[T](p: proc (x: T), x: T) =
when T is void:
p()
@@ -52,15 +51,16 @@ The `void` type is particularly useful for generic code:
callProc[int](intProc, 12)
callProc[void](emptyProc)
```
However, a `void` type cannot be inferred in generic code:
.. code-block:: nim
```nim
callProc(emptyProc)
# Error: type mismatch: got (proc ())
# but expected one of:
# callProc(p: proc (T), x: T)
```
The `void` type is only valid for parameters and return types; other symbols
cannot have the type `void`.
@@ -97,9 +97,7 @@ to a choice between `T.foo` and `U.foo`. During overload resolution,
the correct type of `foo` is decided from the context. If the type of `foo` is
ambiguous, a static error will be produced.
.. code-block:: nim
:test: "nim c $1"
```nim test = "nim c $1"
{.experimental: "overloadableEnums".}
type
@@ -124,6 +122,7 @@ ambiguous, a static error will be produced.
of value2: echo "B"
p value2
```
Package level objects
@@ -144,8 +143,7 @@ available.
Example:
.. code-block:: nim
```nim
# module A (in an arbitrary package)
type
Pack.SomeObject = object # declare as incomplete object of package 'Pack'
@@ -154,15 +152,16 @@ Example:
# Incomplete objects can be used as parameters:
proc myproc(x: SomeObject) = discard
```
.. code-block:: nim
```nim
# module B (in package "Pack")
type
SomeObject* {.package.} = object # Use 'package' to complete the object
s, t: string
x, y: int
```
This feature will likely be superseded in the future by support for
recursive module dependencies.
@@ -223,8 +222,7 @@ preface definitions inside a module.
Example:
.. code-block:: nim
```nim
{.experimental: "codeReordering".}
proc foo(x: int) =
@@ -234,14 +232,14 @@ Example:
echo(x)
foo(10)
```
Variables can also be reordered as well. Variables that are *initialized* (i.e.
variables that have their declaration and assignment combined in a single
statement) can have their entire initialization statement reordered. Be wary of
what code is executed at the top level:
.. code-block:: nim
```nim
{.experimental: "codeReordering".}
proc a() =
@@ -250,6 +248,7 @@ what code is executed at the top level:
var foo = 5
a() # outputs: "5"
```
..
TODO: Let's table this for now. This is an *experimental feature* and so the
@@ -260,8 +259,7 @@ what code is executed at the top level:
code reordering process, and not after. As an example, the output of this
code is the same as it would be with code reordering disabled.
.. code-block:: nim
```nim
{.experimental: "codeReordering".}
proc x() =
@@ -270,12 +268,12 @@ what code is executed at the top level:
var foo = 4
x() # "false"
```
It is important to note that reordering *only* works for symbols at top level
scope. Therefore, the following will *fail to compile:*
.. code-block:: nim
```nim
{.experimental: "codeReordering".}
proc a() =
@@ -284,6 +282,7 @@ scope. Therefore, the following will *fail to compile:*
echo("Hello!")
a()
```
This feature will likely be replaced with a better solution to remove
the need for forward declarations.
@@ -295,8 +294,7 @@ Automatic dereferencing
Automatic dereferencing is performed for the first argument of a routine call.
This feature has to be enabled via `{.experimental: "implicitDeref".}`:
.. code-block:: nim
```nim
{.experimental: "implicitDeref".}
type
@@ -309,6 +307,7 @@ This feature has to be enabled via `{.experimental: "implicitDeref".}`:
let n = Node()
echo n.depth
# no need to write n[].depth
```
Special Operators
@@ -333,21 +332,21 @@ for a dot operator that can be matched against a re-written form of
the expression, where the unknown field or proc name is passed to
an `untyped` parameter:
.. code-block:: nim
```nim
a.b # becomes `.`(a, b)
a.b(c, d) # becomes `.`(a, b, c, d)
```
The matched dot operators can be symbols of any callable kind (procs,
templates and macros), depending on the desired effect:
.. code-block:: nim
```nim
template `.`(js: PJsonNode, field: untyped): JSON = js[astToStr(field)]
var js = parseJson("{ x: 1, y: 2}")
echo js.x # outputs 1
echo js.y # outputs 2
```
The following dot operators are available:
@@ -366,9 +365,9 @@ operator `.=`
-------------
This operator will be matched against assignments to missing fields.
.. code-block:: nim
```nim
a.b = c # becomes `.=`(a, b, c)
```
Call operator
-------------
@@ -377,8 +376,7 @@ precedence over dot operators, however it does not match missing overloads
for existing routines. The experimental `callOperator` switch must be enabled
to use this operator.
.. code-block:: nim
```nim
{.experimental: "callOperator".}
template `()`(a: int, b: float): untyped = $(a, b)
@@ -402,6 +400,7 @@ to use this operator.
doAssert not compiles(a.b(c)) # gives a type mismatch error same as b(a, c)
doAssert (a.b)(c) == `()`(a.b, c)
```
Extended macro pragmas
@@ -412,9 +411,10 @@ can also be applied to type, variable and constant declarations.
For types:
.. code-block:: nim
```nim
type
MyObject {.schema: "schema.protobuf".} = object
```
This is translated to a call to the `schema` macro with a `nnkTypeDef`
AST node capturing the left-hand side, remaining pragmas and the right-hand
@@ -437,19 +437,21 @@ For variables and constants, it is largely the same, except a unary node with
the same kind as the section containing a single definition is passed to macros,
and macros can return any expression.
.. code-block:: nim
```nim
var
a = ...
b {.importc, foo, nodecl.} = ...
c = ...
```
Assuming `foo` is a macro or a template, this is roughly equivalent to:
.. code-block:: nim
```nim
var a = ...
foo:
var b {.importc, nodecl.} = ...
var c = ...
```
Symbols as template/macro calls
@@ -459,7 +461,7 @@ Templates and macros that take no arguments can be called as lone symbols,
i.e. without parentheses. This is useful for repeated uses of complex
expressions that cannot conveniently be represented as runtime values.
.. code-block:: nim
```nim
type Foo = object
bar: int
@@ -468,6 +470,7 @@ expressions that cannot conveniently be represented as runtime values.
assert bar == 10
bar = 15
assert bar == 15
```
In the future, this may require more specific information on template or macro
signatures to be used. Specializations for some applications of this may also
@@ -483,8 +486,7 @@ Not nil annotation
All types for which `nil` is a valid value can be annotated with the
`not nil` annotation to exclude `nil` as a valid value:
.. code-block:: nim
```nim
{.experimental: "notnil".}
type
@@ -500,6 +502,7 @@ All types for which `nil` is a valid value can be annotated with the
# and also this:
var x: PObject
p(x)
```
The compiler ensures that every code path initializes variables which contain
non-nilable pointers. The details of this analysis are still to be specified
@@ -545,8 +548,7 @@ via a parameter that is not declared as a `var` parameter.
For example:
.. code-block:: nim
```nim
{.experimental: "strictFuncs".}
type
@@ -566,6 +568,7 @@ For example:
m.data = "yeah" # the mutation is here
# Error: 'mut' can have side effects
# an object reachable from 'n' is potentially mutated
```
The algorithm behind this analysis is described in
@@ -585,23 +588,23 @@ A view type is a type that is or contains one of the following types:
For example:
.. code-block:: nim
```nim
type
View1 = openArray[byte]
View2 = lent string
View3 = Table[openArray[char], int]
```
Exceptions to this rule are types constructed via `ptr` or `proc`.
For example, the following types are **not** view types:
.. code-block:: nim
```nim
type
NotView1 = proc (x: openArray[int])
NotView2 = ptr openArray[char]
NotView3 = ptr array[4, lent int]
```
The mutability aspect of a view type is not part of the type but part
@@ -618,8 +621,7 @@ it was borrowed from.
For example:
.. code-block:: nim
```nim
{.experimental: "views".}
proc take(a: openArray[int]) =
@@ -641,6 +643,7 @@ For example:
main(@[11, 22, 33])
```
A local variable of a view type can borrow from a location
@@ -699,8 +702,7 @@ For the duration of the borrow operation, no mutations to the borrowed locations
may be performed except via the view that borrowed from the
location. The borrowed location is said to be *sealed* during the borrow.
.. code-block:: nim
```nim
{.experimental: "views".}
type
@@ -711,16 +713,17 @@ location. The borrowed location is said to be *sealed* during the borrow.
let v: lent Obj = s[0] # seal 's'
s.setLen 0 # prevented at compile-time because 's' is sealed.
echo v.field
```
The scope of the view does not matter:
.. code-block:: nim
```nim
proc valid(s: var seq[Obj]) =
let v: lent Obj = s[0] # begin of borrow
echo v.field # end of borrow
s.setLen 0 # valid because 'v' isn't used afterwards
```
The analysis requires as much precision about mutations as is reasonably obtainable,
@@ -730,13 +733,13 @@ with `--experimental:strictFuncs`:option:.
The analysis is currently control flow insensitive:
.. code-block:: nim
```nim
proc invalid(s: var seq[Obj]) =
let v: lent Obj = s[0]
if false:
s.setLen 0
echo v.field
```
In this example, the compiler assumes that `s.setLen 0` invalidates the
borrow operation of `v` even though a human being can easily see that it
@@ -824,8 +827,7 @@ arbitrary set of requirements that the matched type must satisfy.
Concepts are written in the following form:
.. code-block:: nim
```nim
type
Comparable = concept x, y
(x < y) is bool
@@ -838,6 +840,7 @@ Concepts are written in the following form:
for value in s:
value is T
```
The concept matches if:
@@ -850,29 +853,28 @@ as `var`, `ref`, `ptr` and `static` to denote a more specific type of
instance. You can also apply the `type` modifier to create a named instance of
the type itself:
.. code-block:: nim
```nim
type
MyConcept = concept x, var v, ref r, ptr p, static s, type T
...
```
Within the concept body, types can appear in positions where ordinary values
and parameters are expected. This provides a more convenient way to check for
the presence of callable symbols with specific signatures:
.. code-block:: nim
```nim
type
OutputStream = concept var s
s.write(string)
```
In order to check for symbols accepting `type` params, you must prefix
the type with the explicit `type` modifier. The named instance of the
type, following the `concept` keyword is also considered to have the
explicit modifier and will be matched only as a type.
.. code-block:: nim
```nim
type
# Let's imagine a user-defined casting framework with operators
# such as `val.to(string)` and `val.to(JSonValue)`. We can test
@@ -890,6 +892,7 @@ explicit modifier and will be matched only as a type.
x is AdditiveMonoid
-x is T
x - y is T
```
Please note that the `is` operator allows one to easily verify the precise
type signatures of the required operations, but since type inference and
@@ -909,12 +912,12 @@ When you need to understand why the compiler is not matching a particular
concept and, as a result, a wrong overload is selected, you can apply the
`explain` pragma to either the concept body or a particular call-site.
.. code-block:: nim
```nim
type
MyConcept {.explain.} = concept ...
overloadedProc(x, y, z) {.explain.}
```
This will provide Hints in the compiler output either every time the concept is
not matched or only on the particular call-site.
@@ -925,8 +928,7 @@ Generic concepts and type binding rules
The concept types can be parametric just like the regular generic types:
.. code-block:: nim
```nim
### matrixalgo.nim
import std/typetraits
@@ -986,6 +988,7 @@ The concept types can be parametric just like the regular generic types:
echo m.transposed.determinant
setPerspectiveProjection projectionMatrix
```
When the concept type is matched against a concrete type, the unbound type
parameters are inferred from the body of the concept in a way that closely
@@ -999,11 +1002,11 @@ and `x.data is seq[T]`.
Unbound static params will be inferred from expressions involving the `==`
operator and also when types dependent on them are being matched:
.. code-block:: nim
```nim
type
MatrixReducer[M, N: static int; T] = concept x
x.reduce(SquareMatrix[N, T]) is array[M, int]
```
The Nim compiler includes a simple linear equation solver, allowing it to
infer static params in some situations where integer arithmetic is involved.
@@ -1014,8 +1017,7 @@ modifier to any of the otherwise inferable types to get a type that will be
matched without permanently inferring it. This may be useful when you need
to match several procs accepting the same wide class of types:
.. code-block:: nim
```nim
type
Enumerable[T] = concept e
for v in e:
@@ -1032,13 +1034,13 @@ to match several procs accepting the same wide class of types:
# it's also possible to give an alias name to a `bind many` type class
type Enum = distinct Enumerable
o.baz is Enum
```
On the other hand, using `bind once` types allows you to test for equivalent
types used in multiple signatures, without actually requiring any concrete
types, thus allowing you to encode implementation-defined types:
.. code-block:: nim
```nim
type
MyConcept = concept x
type T1 = auto
@@ -1049,6 +1051,7 @@ types, thus allowing you to encode implementation-defined types:
x.alpha(T2)
x.omega(T2) # both procs must accept the same type
# and it must be a numeric sequence
```
As seen in the previous examples, you can refer to generic concepts such as
`Enumerable[T]` just by their short name. Much like the regular generic types,
@@ -1066,9 +1069,7 @@ in any required way. For example, here is how one might define the classic
`Functor` concept from Haskell and then demonstrate that Nim's `Option[T]`
type is an instance of it:
.. code-block:: nim
:test: "nim c $1"
```nim test = "nim c $1"
import std/[sugar, typetraits]
type
@@ -1089,6 +1090,7 @@ type is an instance of it:
import std/options
echo Option[int] is Functor # prints true
```
Concept derived values
@@ -1098,8 +1100,7 @@ All top level constants or types appearing within the concept body are
accessible through the dot operator in procs where the concept was successfully
matched to a concrete type:
.. code-block:: nim
```nim
type
DateTime = concept t1, t2, type T
const Min = T.MinDate
@@ -1121,6 +1122,7 @@ matched to a concrete type:
deviation: float
...
```
Concept refinement
@@ -1133,8 +1135,7 @@ overload resolution, Nim will assign a higher precedence to the most specific
one. As an alternative way of defining concept refinements, you can use the
object inheritance syntax involving the `of` keyword:
.. code-block:: nim
```nim
type
Graph = concept g, type G of EquallyComparable, Copyable
type
@@ -1168,6 +1169,7 @@ object inheritance syntax involving the `of` keyword:
proc f(g: IncidendeGraph)
proc f(g: BidirectionalGraph) # this one will be preferred if we pass a type
# matching the BidirectionalGraph concept
```
..
Converter type classes
@@ -1177,8 +1179,7 @@ object inheritance syntax involving the `of` keyword:
a small set of simpler types. This is achieved with a `return` statement within
the concept body:
.. code-block:: nim
```nim
type
Stringable = concept x
$x is string
@@ -1202,6 +1203,7 @@ object inheritance syntax involving the `of` keyword:
# the same call at the cost of additional instantiations
# the varargs param will be converted to a tuple
proc log(format: static string, varargs[distinct StringRef])
```
..
@@ -1229,8 +1231,7 @@ object inheritance syntax involving the `of` keyword:
a converter type class, which converts the regular instances of the matching
types to the corresponding VTable type.
.. code-block:: nim
```nim
type
IntEnumerable = vtref Enumerable[int]
@@ -1243,6 +1244,7 @@ object inheritance syntax involving the `of` keyword:
proc addStream(o: var MyObject, e: OutputStream.vtref) =
o.streams.add e
```
The procs that will be included in the vtable are derived from the concept
body and include all proc calls for which all param types were specified as
@@ -1272,9 +1274,9 @@ object inheritance syntax involving the `of` keyword:
The signature has to be:
.. code-block:: nim
```nim
proc `=deepCopy`(x: T): T
```
This mechanism will be used by most data structures that support shared memory,
like channels, to implement thread safe automatic memory management.
@@ -1289,7 +1291,7 @@ Dynamic arguments for bindSym
This experimental feature allows the symbol name argument of `macros.bindSym`
to be computed dynamically.
.. code-block:: nim
```nim
{.experimental: "dynamicBindSym".}
import macros
@@ -1299,6 +1301,7 @@ to be computed dynamically.
echo callOp("+", 1, 2)
echo callOp("-", 5, 4)
```
Term rewriting macros
@@ -1309,12 +1312,12 @@ a *name* but also a *pattern* that is searched for after the semantic checking
phase of the compiler: This means they provide an easy way to enhance the
compilation pipeline with user defined optimizations:
.. code-block:: nim
```nim
template optMul{`*`(a, 2)}(a: int): int = a + a
let x = 3
echo x * 2
```
The compiler now rewrites `x * 2` as `x + x`. The code inside the
curly brackets is the pattern to match against. The operators `*`, `**`,
@@ -1332,8 +1335,7 @@ Once this limit has been passed, the term rewriting macro will be ignored.
Unfortunately optimizations are hard to get right and even this tiny example
is **wrong**:
.. code-block:: nim
```nim
template optMul{`*`(a, 2)}(a: int): int = a + a
proc f(): int =
@@ -1341,12 +1343,12 @@ is **wrong**:
result = 55
echo f() * 2
```
We cannot duplicate 'a' if it denotes an expression that has a side effect!
Fortunately Nim supports side effect analysis:
.. code-block:: nim
```nim
template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a + a
proc f(): int =
@@ -1354,6 +1356,7 @@ Fortunately Nim supports side effect analysis:
result = 55
echo f() * 2 # not optimized ;-)
```
You can make one overload matching with a constraint and one without, and the
one with a constraint will have precedence, and so you can handle both cases
@@ -1363,15 +1366,15 @@ So what about `2 * a`? We should tell the compiler `*` is commutative. We
cannot really do that however as the following code only swaps arguments
blindly:
.. code-block:: nim
```nim
template mulIsCommutative{`*`(a, b)}(a, b: int): int = b * a
```
What optimizers really need to do is a *canonicalization*:
.. code-block:: nim
```nim
template canonMul{`*`(a, b)}(a: int{lit}, b: int): int = b * a
```
The `int{lit}` parameter pattern matches against an expression of
type `int`, but only if it's a literal.
@@ -1429,17 +1432,16 @@ The `alias` and `noalias` predicates refer not only to the matching AST,
but also to every other bound parameter; syntactically they need to occur after
the ordinary AST predicates:
.. code-block:: nim
```nim
template ex{a = b + c}(a: int{noalias}, b, c: int) =
# this transformation is only valid if 'b' and 'c' do not alias 'a':
a = b
inc a, c
```
Another example:
.. code-block:: nim
```nim
proc somefunc(s: string) = assert s == "variable"
proc somefunc(s: string{nkStrLit}) = assert s == "literal"
proc somefunc(s: string{nkRStrLit}) = assert s == r"raw"
@@ -1454,6 +1456,7 @@ Another example:
somefunc("literal")
somefunc(r"raw")
somefunc("""triple""")
```
Pattern operators
@@ -1467,21 +1470,21 @@ if they are written in infix notation.
The `|` operator if used as infix operator creates an ordered choice:
.. code-block:: nim
```nim
template t{0|1}(): untyped = 3
let a = 1
# outputs 3:
echo a
```
The matching is performed after the compiler performed some optimizations like
constant folding, so the following does not work:
.. code-block:: nim
```nim
template t{0|1}(): untyped = 3
# outputs 1:
echo 1
```
The reason is that the compiler already transformed the 1 into "1" for
the `echo` statement. However, a term rewriting macro should not change the
@@ -1494,20 +1497,19 @@ command line option or temporarily with the `patterns` pragma.
A pattern expression can be bound to a pattern parameter via the `expr{param}`
notation:
.. code-block:: nim
```nim
template t{(0|1|2){x}}(x: untyped): untyped = x + 1
let a = 1
# outputs 2:
echo a
```
### The `~` operator
The `~` operator is the 'not' operator in patterns:
.. code-block:: nim
```nim
template t{x = (~x){y} and (~x){z}}(x, y, z: bool) =
x = y
if x: x = z
@@ -1518,6 +1520,7 @@ The `~` operator is the 'not' operator in patterns:
c = false
a = b and c
echo a
```
### The `*` operator
@@ -1525,8 +1528,7 @@ The `~` operator is the 'not' operator in patterns:
The `*` operator can *flatten* a nested binary expression like `a & b & c`
to `&(a, b, c)`:
.. code-block:: nim
```nim
var
calls = 0
@@ -1542,6 +1544,7 @@ to `&(a, b, c)`:
# check that it's been optimized properly:
doAssert calls == 1
```
The second operator of `*` must be a parameter; it is used to gather all the
@@ -1550,9 +1553,9 @@ is passed to `optConc` in `a` as a special list (of kind `nkArgList`)
which is flattened into a call expression; thus the invocation of `optConc`
produces:
.. code-block:: nim
`&&`("my", space & "awe", "some ", "concat")
```nim
`&&`("my", space & "awe", "some ", "concat")
```
### The `**` operator
@@ -1560,8 +1563,7 @@ produces:
The `**` is much like the `*` operator, except that it gathers not only
all the arguments, but also the matched operators in reverse polish notation:
.. code-block:: nim
```nim
import std/macros
type
@@ -1582,6 +1584,7 @@ all the arguments, but also the matched operators in reverse polish notation:
var x, y, z: Matrix
echo x + y * z - x
```
This passes the expression `x + y * z - x` to the `optM` macro as
an `nnkArgList` node containing::
@@ -1605,13 +1608,13 @@ Parameters in a pattern are type checked in the matching process. If a
parameter is of the type `varargs`, it is treated specially and can match
0 or more arguments in the AST to be matched against:
.. code-block:: nim
```nim
template optWrite{
write(f, x)
((write|writeLine){w})(f, y)
}(x, y: varargs[untyped], f: File, w: untyped) =
w(f, x, y)
```
noRewrite pragma
@@ -1625,12 +1628,12 @@ e.g. when rewriting term to same term plus extra content.
`noRewrite` pragma can actually prevent further rewriting on marked code,
e.g. with given example `echo("ab")` will be rewritten just once:
.. code-block:: nim
```nim
template pwnEcho{echo(x)}(x: untyped) =
{.noRewrite.}: echo("pwned!")
echo "ab"
```
`noRewrite` pragma can be useful to control term-rewriting macros recursion.
@@ -1642,13 +1645,13 @@ Example: Partial evaluation
The following example shows how some simple partial evaluation can be
implemented with term rewriting:
.. code-block:: nim
```nim
proc p(x, y: int; cond: bool): int =
result = if cond: x + y else: x - y
template optP1{p(x, y, true)}(x, y: untyped): untyped = x + y
template optP2{p(x, y, false)}(x, y: untyped): untyped = x - y
```
Example: Hoisting
@@ -1656,8 +1659,7 @@ Example: Hoisting
The following example shows how some form of hoisting can be implemented:
.. code-block:: nim
```nim
import std/pegs
template optPeg{peg(pattern)}(pattern: string{lit}): Peg =
@@ -1667,6 +1669,7 @@ The following example shows how some form of hoisting can be implemented:
for i in 0 .. 3:
echo match("(a b c)", peg"'(' @ ')'")
echo match("W_HI_Le", peg"\y 'while'")
```
The `optPeg` template optimizes the case of a peg constructor with a string
literal, so that the pattern will only be parsed once at program startup and
@@ -1680,8 +1683,7 @@ AST based overloading
Parameter constraints can also be used for ordinary routine parameters; these
constraints then affect ordinary overloading resolution:
.. code-block:: nim
```nim
proc optLit(a: string{lit|`const`}) =
echo "string literal"
proc optLit(a: string) =
@@ -1696,6 +1698,7 @@ constraints then affect ordinary overloading resolution:
optLit("literal")
optLit(constant)
optLit(variable)
```
However, the constraints `alias` and `noalias` are not available in
ordinary routines.
@@ -1735,8 +1738,7 @@ Spawn statement
The `spawn`:idx: statement can be used to pass a task to the thread pool:
.. code-block:: nim
```nim
import std/threadpool
proc processLine(line: string) =
@@ -1745,6 +1747,7 @@ The `spawn`:idx: statement can be used to pass a task to the thread pool:
for x in lines("myinput.txt"):
spawn processLine(x)
sync()
```
For reasons of type safety and implementation simplicity the expression
that `spawn` takes is restricted:
@@ -1768,8 +1771,7 @@ a `data flow variable`:idx: `FlowVar[T]` that can be read from. The reading
with the `^` operator is **blocking**. However, one can use `blockUntilAny` to
wait on multiple flow variables at the same time:
.. code-block:: nim
```nim
import std/threadpool, ...
# wait until 2 out of 3 servers received the update:
@@ -1781,6 +1783,7 @@ wait on multiple flow variables at the same time:
assert index >= 0
responses.del(index)
discard blockUntilAny(responses)
```
Data flow variables ensure that no data races are possible. Due to
technical limitations, not every type `T` can be used in
@@ -1795,9 +1798,7 @@ Parallel statement
Example:
.. code-block:: nim
:test: "nim c --threads:on $1"
```nim test = "nim c --threads:on $1"
# Compute pi in an inefficient way
import std/[strutils, math, threadpool]
{.experimental: "parallel".}
@@ -1813,6 +1814,7 @@ Example:
result += ch[k]
echo formatFloat(pi(5000))
```
The parallel statement is the preferred mechanism to introduce parallelism in a
@@ -1853,8 +1855,7 @@ lock of level `N < M`. Another lock of level `M` cannot be acquired. Locks
of the same level can only be acquired *at the same time* within a
single `locks` section:
.. code-block:: nim
```nim
var a, b: TLock[2]
var x: TLock[1]
# invalid locking order: TLock[1] cannot be acquired before TLock[2]:
@@ -1874,14 +1875,14 @@ single `locks` section:
# valid locking order, locks of the same level acquired at the same time:
{.locks: [a, b].}:
...
```
Here is how a typical multilock statement can be implemented in Nim. Note how
the runtime check is required to ensure a global ordering for two locks `a`
and `b` of the same lock level:
.. code-block:: nim
```nim
template multilock(a, b: ptr TLock; body: untyped) =
if cast[ByteAddress](a) < cast[ByteAddress](b):
pthread_mutex_lock(a)
@@ -1895,20 +1896,21 @@ and `b` of the same lock level:
finally:
pthread_mutex_unlock(a)
pthread_mutex_unlock(b)
```
Whole routines can also be annotated with a `locks` pragma that takes a lock
level. This then means that the routine may acquire locks of up to this level.
This is essential so that procs can be called within a `locks` section:
.. code-block:: nim
```nim
proc p() {.locks: 3.} = discard
var a: TLock[4]
{.locks: [a].}:
# p's locklevel (3) is strictly less than a's (4) so the call is allowed:
p()
```
As usual, `locks` is an inferred effect and there is a subtype
@@ -1924,8 +1926,7 @@ cannot be inferred statically, leading to compiler warnings. By using
`{.locks: "unknown".}`, the base method can be marked explicitly as
having unknown lock level as well:
.. code-block:: nim
```nim
type SomeBase* = ref object of RootObj
type SomeDerived* = ref object of SomeBase
memberProc*: proc ()
@@ -1934,5 +1935,6 @@ having unknown lock level as well:
method testMethod(g: SomeDerived) =
if g.memberProc != nil:
g.memberProc()
```
This feature may be removed in the future due to its practical difficulties.