new doc terminology for "compile-time" and "runtime" (#10497)

* First pass at compile-time/runtime terminology changes.

* Solid edit pass on changes and successful rst2html; still need to review HTML output.

* Finished this terminology update.

* Incorporated Araq's initial feedback.
This commit is contained in:
Andreas Rumpf 2019-01-31 16:19:19 +01:00 • committed by GitHub
commit c268bfd5a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -46,8 +46,8 @@ and ``a ^* b`` is short for ``(a (b a)*)?``. Example::
arrayConstructor = '[' expr ^* ',' ']' arrayConstructor = '[' expr ^* ',' ']'
Other parts of Nim - like scoping rules or runtime semantics are only Other parts of Nim, like scoping rules or runtime semantics, are
described in the, more easily comprehensible, informal manner for now. described informally.
@ -55,7 +55,7 @@ described in the, more easily comprehensible, informal manner for now.
Definitions Definitions
=========== ===========
A Nim program specifies a computation that acts on a memory consisting of Nim code specifies a computation that acts on a memory consisting of
components called `locations`:idx:. A variable is basically a name for a components called `locations`:idx:. A variable is basically a name for a
location. Each variable and location is of a certain `type`:idx:. The location. Each variable and location is of a certain `type`:idx:. The
variable's type is called `static type`:idx:, the location's type is called variable's type is called `static type`:idx:, the location's type is called
@ -71,21 +71,40 @@ identifier is declared unless overloading resolution rules suggest otherwise.
An expression specifies a computation that produces a value or location. An expression specifies a computation that produces a value or location.
Expressions that produce locations are called `l-values`:idx:. An l-value Expressions that produce locations are called `l-values`:idx:. An l-value
can denote either a location or the value the location contains, depending on can denote either a location or the value the location contains, depending on
the context. Expressions whose values can be determined statically are called the context.
`constant expressions`:idx:; they are never l-values.
A `static error`:idx: is an error that the implementation detects before A Nim `program`:idx: consists of one or more text `source files`:idx: containing
program execution. Unless explicitly classified, an error is a static error. Nim code. It is processed by a Nim `compiler`:idx: into an `executable`:idx:.
The nature of this executable depends on the compiler implementation; it may,
for example, be a native binary or JavaScript source code.
In a typical Nim program, most of the code is compiled into the executable.
However, some of the code may be executed at
`compile time`:idx:. This can include constant expressions, macro definitions,
and Nim procedures used by macro definitions. Most of the Nim language is
supported at compile time, but there are some restrictions -- see `Restrictions
on Compile-Time Execution <#restrictions-on-compileminustime-execution>`_ for
details. We use the term `runtime`:idx: to cover both compile-time execution
and code execution in the executable.
The compiler parses Nim source code into an internal data structure called the
`abstract syntax tree`:idx: (`AST`:idx:). Then, before executing the code or
compiling it into the executable, it transforms the AST through `semantic
analysis`:idx:. This adds semantic information such as expression types,
identifier meanings, and in some cases expression values. An error detected
during semantic analysis is called a `static error`:idx:. Errors described in
this manual are static errors when not otherwise specified.
A `checked runtime error`:idx: is an error that the implementation detects A `checked runtime error`:idx: is an error that the implementation detects
and reports at runtime. The method for reporting such errors is via *raising and reports at runtime. The method for reporting such errors is via
exceptions* or *dying with a fatal error*. However, the implementation *raising exceptions* or *dying with a fatal error*. However, the implementation
provides a means to disable these runtime checks. See the section pragmas_ provides a means to disable these `runtime checks`:idx:. See the section
for details. pragmas_ for details.
Whether a checked runtime error results in an exception or in a fatal error at Whether a checked runtime error results in an exception or in a fatal error is
runtime is implementation specific. Thus the following program is always implementation specific. Thus the following program is invalid; even though the
invalid: code purports to catch the `IndexError` from an out-of-bounds array access, the
compiler may instead choose to allow the program to die with a fatal error.
.. code-block:: nim .. code-block:: nim
var a: array[0..1, char] var a: array[0..1, char]
@ -98,8 +117,23 @@ invalid:
An `unchecked runtime error`:idx: is an error that is not guaranteed to be An `unchecked runtime error`:idx: is an error that is not guaranteed to be
detected, and can cause the subsequent behavior of the computation to detected, and can cause the subsequent behavior of the computation to
be arbitrary. Unchecked runtime errors cannot occur if only `safe`:idx: be arbitrary. Unchecked runtime errors cannot occur if only `safe`:idx:
language features are used. language features are used and if no runtime checks are disabled.
A `constant expression`:idx: is an expression whose value can be computed during
semantic analysis of the code in which it appears. It is never an l-value and
never has side effects. Constant expressions are not limited to the capabilities
of semantic analysis, such as constant folding; they can use all Nim language
features that are supported for compile-time execution. Since constant
expressions can be used as an input to semantic analysis (such as for defining
array bounds), this flexibility requires the compiler to interleave semantic
analysis and compile-time code execution.
It is mostly accurate to picture semantic analysis proceeding top to bottom and
left to right in the source code, with compile-time code execution interleaved
when necessary to compute values that are required for subsequent semantic
analysis. We will see much later in this document that macro invocation not only
requires this interleaving, but also creates a situation where semantic analyis
does not entirely proceed top to bottom and left to right.
Lexical Analysis Lexical Analysis
@ -677,10 +711,87 @@ Rationale: Consistency with overloaded assignment or assignment-like operations,
``a = b`` can be read as ``performSomeCopy(a, b)``. ``a = b`` can be read as ``performSomeCopy(a, b)``.
Constants and Constant Expressions
==================================
A `constant`:idx: is a symbol that is bound to the value of a constant
expression. Constant expressions are restricted to depend only on the following
categories of values and operations, because these are either built into the
language or declared and evaluated before semantic analysis of the constant
expression:
* literals
* built-in operators
* previously declared constants and compile-time variables
* previously declared macros and templates
* previously declared procedures that have no side effects beyond
possibly modifying compile-time variables
A constant expression can contain code blocks that may internally use all Nim
features supported at compile time (as detailed in the next section below).
Within such a code block, it is possible to declare variables and then later
read and update them, or declare variables and pass them to procedures that
modify them. However, the code in such a block must still adhere to the
retrictions listed above for referencing values and operations outside the
block.
The ability to access and modify compile-time variables adds flexibility to
constant expressions that may be surprising to those coming from other
statically typed languages. For example, the following code echoes the beginning
of the Fibonacci series **at compile time**. (This is a demonstration of
flexibility in defining constants, not a recommended style for solving this
problem!)
.. code-block:: nim
:test: "nim c $1"
import strformat
var fib_n {.compileTime.}: int
var fib_prev {.compileTime.}: int
var fib_prev_prev {.compileTime.}: int
proc next_fib(): int =
result = if fib_n < 2:
fib_n
else:
fib_prev_prev + fib_prev
inc(fib_n)
fib_prev_prev = fib_prev
fib_prev = result
const f0 = next_fib()
const f1 = next_fib()
const display_fib = block:
const f2 = next_fib()
var result = fmt"Fibonacci sequence: {f0}, {f1}, {f2}"
for i in 3..12:
add(result, fmt", {next_fib()}")
result
static:
echo display_fib
Restrictions on Compile-Time Execution
======================================
Nim code that will be executed at compile time cannot use the following
language features:
* methods
* closure iterators
* the ``cast`` operator
* reference (pointer) types
* the FFI
Some or all of these restrictions are likely to be lifted over time.
Types Types
===== =====
All expressions have a type which is known at compile time. Nim All expressions have a type which is known during semantic analysis. Nim
is statically typed. One can declare new types, which is in essence defining is statically typed. One can declare new types, which is in essence defining
an identifier that can be used to denote this custom type. an identifier that can be used to denote this custom type.
@ -801,8 +912,8 @@ For further details, see `Convertible relation
Subrange types Subrange types
-------------- --------------
A subrange type is a range of values from an ordinal or floating point type (the base A subrange type is a range of values from an ordinal or floating point type (the base
type). To define a subrange type, one must specify it's limiting values: the type). To define a subrange type, one must specify its limiting values -- the
lowest and highest value of the type: lowest and highest value of the type. For example:
.. code-block:: nim .. code-block:: nim
type type
@ -814,8 +925,8 @@ lowest and highest value of the type:
to 5. ``PositiveFloat`` defines a subrange of all positive floating point values. to 5. ``PositiveFloat`` defines a subrange of all positive floating point values.
NaN does not belong to any subrange of floating point types. NaN does not belong to any subrange of floating point types.
Assigning any other value to a variable of type ``Subrange`` is a Assigning any other value to a variable of type ``Subrange`` is a
checked runtime error (or static error if it can be statically checked runtime error (or static error if it can be determined during
determined). Assignments from the base type to one of its subrange types semantic analysis). Assignments from the base type to one of its subrange types
(and vice versa) are allowed. (and vice versa) are allowed.
A subrange type has the same size as its base type (``int`` in the A subrange type has the same size as its base type (``int`` in the
@ -858,7 +969,7 @@ The IEEE standard defines five types of floating-point exceptions:
* Inexact: operation produces a result that cannot be represented with infinite * Inexact: operation produces a result that cannot be represented with infinite
precision, for example, 2.0 / 3.0, log(1.1) and 0.1 in input. precision, for example, 2.0 / 3.0, log(1.1) and 0.1 in input.
The IEEE exceptions are either ignored at runtime or mapped to the The IEEE exceptions are either ignored during execution or mapped to the
Nim exceptions: `FloatInvalidOpError`:idx:, `FloatDivByZeroError`:idx:, Nim exceptions: `FloatInvalidOpError`:idx:, `FloatDivByZeroError`:idx:,
`FloatOverflowError`:idx:, `FloatUnderflowError`:idx:, `FloatOverflowError`:idx:, `FloatUnderflowError`:idx:,
and `FloatInexactError`:idx:. and `FloatInexactError`:idx:.
@ -885,8 +996,9 @@ The only operations that are affected by the ``floatChecks`` pragma are
the ``+``, ``-``, ``*``, ``/`` operators for floating point types. the ``+``, ``-``, ``*``, ``/`` operators for floating point types.
An implementation should always use the maximum precision available to evaluate An implementation should always use the maximum precision available to evaluate
floating pointer values at compile time; this means expressions like floating pointer values during semantic analysis; this means expressions like
``0.09'f32 + 0.01'f32 == 0.09'f64 + 0.01'f64`` are true. ``0.09'f32 + 0.01'f32 == 0.09'f64 + 0.01'f64`` that are evaluating during
constant folding are true.
Boolean type Boolean type
@ -1113,9 +1225,9 @@ tuples, objects and sets belong to the structured types.
Array and sequence types Array and sequence types
------------------------ ------------------------
Arrays are a homogeneous type, meaning that each element in the array Arrays are a homogeneous type, meaning that each element in the array has the
has the same type. Arrays always have a fixed length which is specified at same type. Arrays always have a fixed length specified as a constant expression
compile time (except for open arrays). They can be indexed by any ordinal type. (except for open arrays). They can be indexed by any ordinal type.
A parameter ``A`` may be an *open array*, in which case it is indexed by A parameter ``A`` may be an *open array*, in which case it is indexed by
integers from 0 to ``len(A)-1``. An array expression may be constructed by the integers from 0 to ``len(A)-1``. An array expression may be constructed by the
array constructor ``[]``. The element type of this array expression is array constructor ``[]``. The element type of this array expression is
@ -1157,7 +1269,7 @@ operator, and remove (and get) the last element of a sequence with the
The notation ``x[i]`` can be used to access the i-th element of ``x``. The notation ``x[i]`` can be used to access the i-th element of ``x``.
Arrays are always bounds checked (at compile-time or at runtime). These Arrays are always bounds checked (statically or at runtime). These
checks can be disabled via pragmas or invoking the compiler with the checks can be disabled via pragmas or invoking the compiler with the
``--boundChecks:off`` command line switch. ``--boundChecks:off`` command line switch.
@ -1320,10 +1432,10 @@ can also be defined with indentation instead of ``[]``:
name: string # a person consists of a name name: string # a person consists of a name
age: natural # and an age age: natural # and an age
Objects provide many features that tuples do not. Object provide inheritance Objects provide many features that tuples do not. Object provide inheritance and
and information hiding. Objects have access to their type at runtime, so that information hiding. Objects have access to their type during at runtime, so that
the ``of`` operator can be used to determine the object's type. The ``of`` operator the ``of`` operator can be used to determine the object's type. The ``of``
is similar to the ``instanceof`` operator in Java. operator is similar to the ``instanceof`` operator in Java.
.. code-block:: nim .. code-block:: nim
type type
@ -1418,8 +1530,8 @@ In the example the ``kind`` field is called the `discriminator`:idx:\: For
safety its address cannot be taken and assignments to it are restricted: The safety its address cannot be taken and assignments to it are restricted: The
new value must not lead to a change of the active object branch. For an object new value must not lead to a change of the active object branch. For an object
branch switch ``system.reset`` has to be used. Also, when the fields of a branch switch ``system.reset`` has to be used. Also, when the fields of a
particular branch are specified during object construction, the correct value particular branch are specified during object construction, the corresponding
for the discriminator must be supplied at compile-time. discriminator value must be specified as a constant expression.
Package level objects Package level objects
--------------------- ---------------------
@ -1433,8 +1545,8 @@ contexts (``var/ref/ptr IncompleteObject``) in general since the compiler does
not yet know the size of the object. To complete an incomplete object not yet know the size of the object. To complete an incomplete object
the ``package`` pragma has to be used. ``package`` implies ``byref``. the ``package`` pragma has to be used. ``package`` implies ``byref``.
As long as a type ``T`` is incomplete ``sizeof(T)`` or "runtime type As long as a type ``T`` is incomplete, neither ``sizeof(T)`` nor runtime
information" for ``T`` is not available. type information for ``T`` is available.
Example: Example:
@ -1863,7 +1975,7 @@ that don't. Distinct types provide a means to introduce a new string type
username: string username: string
db.query("SELECT FROM users WHERE name = '$1'" % username) db.query("SELECT FROM users WHERE name = '$1'" % username)
# Error at compile time: `query` expects an SQL string! # Static error: `query` expects an SQL string!
It is an essential property of abstract types that they **do not** imply a It is an essential property of abstract types that they **do not** imply a
@ -2250,7 +2362,8 @@ Overloading resolution
====================== ======================
In a call ``p(args)`` the routine ``p`` that matches best is selected. If In a call ``p(args)`` the routine ``p`` that matches best is selected. If
multiple routines match equally well, the ambiguity is reported at compiletime. multiple routines match equally well, the ambiguity is reported during
semantic analysis.
Every arg in args needs to match. There are multiple different categories how an Every arg in args needs to match. There are multiple different categories how an
argument can match. Let ``f`` be the formal parameter's type and ``a`` the type argument can match. Let ``f`` be the formal parameter's type and ``a`` the type
@ -2631,53 +2744,36 @@ identifier ``_`` can be used to ignore some parts of the tuple:
Const section Const section
------------- -------------
`Constants`:idx: are symbols which are bound to a value. The constant's value A const section declares constants whose values are constant expressions:
cannot change. The compiler must be able to evaluate the expression in a
constant declaration at compile time.
Nim contains a sophisticated compile-time evaluator, so procedures which .. code-block::
have no side-effect can be used in constant expressions too:
.. code-block:: nim
import strutils import strutils
const const
roundPi = 3.1415
constEval = contains("abc", 'b') # computed at compile time! constEval = contains("abc", 'b') # computed at compile time!
Once declared, a constant's symbol can be used as a constant expression.
The rules for compile-time computability are: See `Constants and Constant Expressions <#constants-and-constant-expressions>`_
for details.
1. Literals are compile-time computable.
2. Type conversions are compile-time computable.
3. Procedure calls of the form ``p(X)`` are compile-time computable if
``p`` is a proc without side-effects (see the `noSideEffect pragma
<#pragmas-nosideeffect-pragma>`_ for details) and if ``X`` is a
(possibly empty) list of compile-time computable arguments.
Constants cannot be of type ``ptr``, ``ref`` or ``var``, nor can
they contain such a type.
Static statement/expression Static statement/expression
--------------------------- ---------------------------
A static statement/expression can be used to enforce compile A static statement/expression explicitly requires compile-time execution.
time evaluation explicitly. Enforced compile time evaluation can even evaluate Even some code that has side effects is permitted in a static block:
code that has side effects:
.. code-block:: .. code-block::
static: static:
echo "echo at compile time" echo "echo at compile time"
It's a static error if the compiler cannot perform the evaluation at compile There are limitations on what Nim code can be executed at compile time;
see `Restrictions on Compile-Time Execution
<#restrictions-on-compileminustime-execution>`_ for details.
It's a static error if the compiler cannot execute the block at compile
time. time.
The current implementation poses some restrictions for compile time
evaluation: Code which contains ``cast`` or makes use of the foreign function
interface cannot be evaluated at compile time. Later versions of Nim will
support the FFI at compile time.
If statement If statement
------------ ------------
@ -2751,9 +2847,9 @@ empty ``discard`` statement should be used.
For non ordinal types it is not possible to list every possible value and so For non ordinal types it is not possible to list every possible value and so
these always require an ``else`` part. these always require an ``else`` part.
As case statements perform compile-time exhaustiveness checks, the value in Because case statements are checked for exhaustiveness during semantic analysis,
every ``of`` branch must be known at compile time. This fact is also exploited the value in every ``of`` branch must be a constant expression.
to generate more performant code. This restriction also allows the compiler to generate more performant code.
As a special semantic extension, an expression in an ``of`` branch of a case As a special semantic extension, an expression in an ``of`` branch of a case
statement may evaluate to a set or array constructor; the set or array is then statement may evaluate to a set or array constructor; the set or array is then
@ -2811,17 +2907,18 @@ When nimvm statement
-------------------- --------------------
``nimvm`` is a special symbol, that may be used as expression of ``when nimvm`` ``nimvm`` is a special symbol, that may be used as expression of ``when nimvm``
statement to differentiate execution path between runtime and compile time. statement to differentiate execution path between compile time and the
executable.
Example: Example:
.. code-block:: nim .. code-block:: nim
proc someProcThatMayRunInCompileTime(): bool = proc someProcThatMayRunInCompileTime(): bool =
when nimvm: when nimvm:
# This code runs in compile time # This branch is taken at compile time.
result = true result = true
else: else:
# This code runs in runtime # This branch is taken in the executable.
result = false result = false
const ctValue = someProcThatMayRunInCompileTime() const ctValue = someProcThatMayRunInCompileTime()
let rtValue = someProcThatMayRunInCompileTime() let rtValue = someProcThatMayRunInCompileTime()
@ -3561,7 +3658,7 @@ returned value is an l-value and can be modified by the caller:
writeAccessToG() = 6 writeAccessToG() = 6
assert g == 6 assert g == 6
It is a compile time error if the implicitly introduced pointer could be It is a static error if the implicitly introduced pointer could be
used to access a location beyond its lifetime: used to access a location beyond its lifetime:
.. code-block:: nim .. code-block:: nim
@ -3677,7 +3774,7 @@ Invocation of a multi-method cannot be ambiguous: collide 2 is preferred over
collide 1 because the resolution works from left to right. collide 1 because the resolution works from left to right.
In the example ``Unit, Thing`` is preferred over ``Thing, Unit``. In the example ``Unit, Thing`` is preferred over ``Thing, Unit``.
**Note**: Compile time evaluation is not (yet) supported for methods. **Note**: Compile-time execution is not (yet) supported for methods.
Inhibit dynamic method resolution via procCall Inhibit dynamic method resolution via procCall
@ -3798,7 +3895,7 @@ In contrast to that, a `closure iterator`:idx: can be passed around more freely:
Closure iterators have other restrictions than inline iterators: Closure iterators have other restrictions than inline iterators:
1. ``yield`` in a closure iterator can not occur in a ``try`` statement. 1. ``yield`` in a closure iterator can not occur in a ``try`` statement.
2. For now, a closure iterator cannot be evaluated at compile time. 2. For now, a closure iterator cannot be executed at compile time.
3. ``return`` is allowed in a closure iterator (but rarely useful) and ends 3. ``return`` is allowed in a closure iterator (but rarely useful) and ends
iteration. iteration.
4. Neither inline nor closure iterators can be recursive. 4. Neither inline nor closure iterators can be recursive.
@ -4117,8 +4214,8 @@ The exception tree is defined in the `system <system.html>`_ module.
Every exception inherits from ``system.Exception``. Exceptions that indicate Every exception inherits from ``system.Exception``. Exceptions that indicate
programming bugs inherit from ``system.Defect`` (which is a subtype of ``Exception``) programming bugs inherit from ``system.Defect`` (which is a subtype of ``Exception``)
and are stricly speaking not catchable as they can also be mapped to an operation and are stricly speaking not catchable as they can also be mapped to an operation
that terminates the whole process. Exceptions that indicate any other runtime error that terminates the whole process. Exceptions that indicate any other runtime
that can be caught inherit from ``system.CatchableError`` error that can be caught inherit from ``system.CatchableError``
(which is a subtype of ``Exception``). (which is a subtype of ``Exception``).
@ -4355,8 +4452,9 @@ a `type variable`:idx:.
Is operator Is operator
----------- -----------
The ``is`` operator checks for type equivalence at compile time. It is The ``is`` operator is evaluated during semantic analysis to check for type
therefore very useful for type specialization within generic code: equivalence. It is therefore very useful for type specialization within generic
code:
.. code-block:: nim .. code-block:: nim
type type
@ -5352,14 +5450,22 @@ chance to convert it into a sequence.
Macros Macros
====== ======
A macro is a special function that is executed at compile-time. A macro is a special function that is executed at compile time.
Normally the input for a macro is an abstract syntax Normally the input for a macro is an abstract syntax
tree (AST) of the code that is passed to it. The macro can then do tree (AST) of the code that is passed to it. The macro can then do
transformations on it and return the transformed AST. The transformations on it and return the transformed AST. This can be used to
transformed AST is then passed to the compiler as if the macro add custom language features and implement `domain specific languages`:idx:.
invocation would have been replaced by its result in the source
code. This can be used to implement `domain specific Macro invocation is a case where semantic analyis does **not** entirely proceed
languages`:idx:. top to bottom and left to right. Instead, semantic analysis happens at least
twice:
* Semantic analysis recognizes and resolves the macro invocation.
* The compiler executes the macro body (which may invoke other procs).
* It replaces the AST of the macro invocation with the AST returned by the macro.
* It repeats semantic analysis of that region of the code.
* If the AST returned by the macro contains other macro invocations,
this process iterates.
While macros enable advanced compile-time code transformations, they While macros enable advanced compile-time code transformations, they
cannot change Nim's syntax. However, this is no real restriction because cannot change Nim's syntax. However, this is no real restriction because
@ -5643,7 +5749,7 @@ static[T]
**Note**: static[T] is still in development. **Note**: static[T] is still in development.
As their name suggests, static parameters must be known at compile-time: As their name suggests, static parameters must be constant expressions:
.. code-block:: nim .. code-block:: nim
@ -5655,7 +5761,7 @@ As their name suggests, static parameters must be known at compile-time:
# regex, stored in a global variable # regex, stored in a global variable
precompiledRegex(paramStr(1)) # Error, command-line options precompiledRegex(paramStr(1)) # Error, command-line options
# are not known at compile-time # are not constant expressions
For the purposes of code generation, all static params are treated as For the purposes of code generation, all static params are treated as
@ -5669,7 +5775,7 @@ Static params can also appear in the signatures of generic types:
type type
Matrix[M,N: static int; T: Number] = array[0..(M*N - 1), T] Matrix[M,N: static int; T: Number] = array[0..(M*N - 1), T]
# Note how `Number` is just a type constraint here, while # Note how `Number` is just a type constraint here, while
# `static int` requires us to supply a compile-time int value # `static int` requires us to supply an int value
AffineTransform2D[T] = Matrix[3, 3, T] AffineTransform2D[T] = Matrix[3, 3, T]
AffineTransform3D[T] = Matrix[4, 4, T] AffineTransform3D[T] = Matrix[4, 4, T]
@ -5677,14 +5783,13 @@ Static params can also appear in the signatures of generic types:
var m1: AffineTransform3D[float] # OK var m1: AffineTransform3D[float] # OK
var m2: AffineTransform2D[string] # Error, `string` is not a `Number` var m2: AffineTransform2D[string] # Error, `string` is not a `Number`
Please note that ``static T`` is just a syntactic convenience for the Please note that ``static T`` is just a syntactic convenience for the underlying
underlying generic type ``static[T]``. The type param can be omitted generic type ``static[T]``. The type param can be omitted to obtain the type
to obtain the type class of all values known at compile-time. A more class of all constant expressions. A more specific type class can be created by
specific type class can be created by instantiating ``static`` with instantiating ``static`` with another type class.
another type class.
You can force the evaluation of a certain expression at compile-time by You can force an expression to be evaluated at compile time as a constant
coercing it to a corresponding ``static`` type: expression by coercing it to a corresponding ``static`` type:
.. code-block:: nim .. code-block:: nim
import math import math
@ -6770,11 +6875,11 @@ pragma block can be used:
compileTime pragma compileTime pragma
------------------ ------------------
The ``compileTime`` pragma is used to mark a proc or variable to be used at The ``compileTime`` pragma is used to mark a proc or variable to be used only
compile time only. No code will be generated for it. Compile time procs are during compile-time execution. No code will be generated for it. Compile-time
useful as helpers for macros. Since version 0.12.0 of the language, a proc procs are useful as helpers for macros. Since version 0.12.0 of the language, a
that uses ``system.NimNode`` within its parameter types is implicitly declared proc that uses ``system.NimNode`` within its parameter types is implicitly
``compileTime``: declared ``compileTime``:
.. code-block:: nim .. code-block:: nim
proc astHelper(n: NimNode): NimNode = proc astHelper(n: NimNode): NimNode =
@ -6861,8 +6966,8 @@ structure:
pure pragma pure pragma
----------- -----------
An object type can be marked with the ``pure`` pragma so that its type An object type can be marked with the ``pure`` pragma so that its type field
field which is used for runtime type identification is omitted. This used to be which is used for runtime type identification is omitted. This used to be
necessary for binary compatibility with other compiled languages. necessary for binary compatibility with other compiled languages.
An enum type can be marked as ``pure``. Then access of its fields always An enum type can be marked as ``pure``. Then access of its fields always
@ -6888,7 +6993,7 @@ though.
The ``error`` pragma can also be used to The ``error`` pragma can also be used to
annotate a symbol (like an iterator or proc). The *usage* of the symbol then annotate a symbol (like an iterator or proc). The *usage* of the symbol then
triggers a compile-time error. This is especially useful to rule out that some triggers a static error. This is especially useful to rule out that some
operation is valid due to overloading and type conversions: operation is valid due to overloading and type conversions:
.. code-block:: nim .. code-block:: nim
@ -7010,7 +7115,7 @@ extension the pragma is simply ignored.
unroll pragma unroll pragma
------------- -------------
The ``unroll`` pragma can be used to tell the compiler that it should unroll The ``unroll`` pragma can be used to tell the compiler that it should unroll
a `for`:idx: or `while`:idx: loop for runtime efficiency: a `for`:idx: or `while`:idx: loop for execution efficiency:
.. code-block:: nim .. code-block:: nim
proc searchChar(s: string, c: char): int = proc searchChar(s: string, c: char): int =
@ -7325,7 +7430,8 @@ compiler like you would using the commandline switch ``--passC``:
{.passC: "-Wall -Werror".} {.passC: "-Wall -Werror".}
Note that you can use ``gorge`` from the `system module <system.html>`_ to Note that you can use ``gorge`` from the `system module <system.html>`_ to
embed parameters from an external command at compile time: embed parameters from an external command that will be executed
during semantic analysis:
.. code-block:: Nim .. code-block:: Nim
{.passC: gorge("pkg-config --cflags sdl").} {.passC: gorge("pkg-config --cflags sdl").}
@ -7339,7 +7445,8 @@ like you would using the commandline switch ``--passL``:
{.passL: "-lSDLmain -lSDL".} {.passL: "-lSDLmain -lSDL".}
Note that you can use ``gorge`` from the `system module <system.html>`_ to Note that you can use ``gorge`` from the `system module <system.html>`_ to
embed parameters from an external command at compile time: embed parameters from an external command that will be executed
during semantic analysis:
.. code-block:: Nim .. code-block:: Nim
{.passL: gorge("pkg-config --libs sdl").} {.passL: gorge("pkg-config --libs sdl").}
@ -7950,7 +8057,7 @@ interoperability with C. Combining packed pragma with inheritance is not
defined, and it should not be used with GC'ed memory (ref's). defined, and it should not be used with GC'ed memory (ref's).
**Future directions**: Using GC'ed memory in packed pragma will result in **Future directions**: Using GC'ed memory in packed pragma will result in
compile-time error. Usage with inheritance should be defined and documented. a static error. Usage with inheritance should be defined and documented.
Dynlib pragma for import Dynlib pragma for import
@ -8231,11 +8338,11 @@ Example:
echo formatFloat(pi(5000)) echo formatFloat(pi(5000))
The parallel statement is the preferred mechanism to introduce parallelism The parallel statement is the preferred mechanism to introduce parallelism in a
in a Nim program. A subset of the Nim language is valid within a Nim program. A subset of the Nim language is valid within a ``parallel``
``parallel`` section. This subset is checked to be free of data races at section. This subset is checked during semantic analysis to be free of data
compile time. A sophisticated `disjoint checker`:idx: ensures that no data races. A sophisticated `disjoint checker`:idx: ensures that no data races are
races are possible even though shared memory is extensively supported! possible even though shared memory is extensively supported!
The subset is in fact the full language with the following The subset is in fact the full language with the following
restrictions / changes: restrictions / changes:
@ -8267,8 +8374,8 @@ pragmas:
1) A `guard`:idx: annotation is introduced to prevent data races. 1) A `guard`:idx: annotation is introduced to prevent data races.
2) Every access of a guarded memory location needs to happen in an 2) Every access of a guarded memory location needs to happen in an
appropriate `locks`:idx: statement. appropriate `locks`:idx: statement.
3) Locks and routines can be annotated with `lock levels`:idx: to prevent 3) Locks and routines can be annotated with `lock levels`:idx: to allow
deadlocks at compile time. potential deadlocks to be detected during semantic analysis.
Guards and the locks section Guards and the locks section
@ -8388,9 +8495,10 @@ This means the following compiles (for now) even though it really should not:
Lock levels Lock levels
----------- -----------
Lock levels are used to enforce a global locking order in order to prevent Lock levels are used to enforce a global locking order in order to detect
deadlocks at compile-time. A lock level is an constant integer in the range potential deadlocks during semantic analysis. A lock level is an constant
0..1_000. Lock level 0 means that no lock is acquired at all. integer in the range 0..1_000. Lock level 0 means that no lock is acquired at
all.
If a section of code holds a lock of level ``M`` than it can also acquire any If a section of code holds a lock of level ``M`` than it can also acquire any
lock of level ``N < M``. Another lock of level ``M`` cannot be acquired. Locks lock of level ``N < M``. Another lock of level ``M`` cannot be acquired. Locks