First pass at compile-time/runtime terminology changes.

This commit is contained in:
deansher 2019-01-28 08:11:59 -05:00
commit 6bae78f365

View file

@ -46,7 +46,7 @@ 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 execution semantics are only
described in the, more easily comprehensible, informal manner for now. described in the, more easily comprehensible, informal manner for now.
@ -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,37 @@ 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. A Nim program can
contain Nim code that will be executed at `compile time`:idx:, such as constant
expressions, macro definitions, and Nim procedures used by macro definitions.
Typically, the bulk of a Nim program's code is compiled into the executable and
executed at `runtime`:idx:. Only a subset of the Nim language is supported at
compile time, but it is a substantial subset. See `Restrictions on
Compile-Time Execution <restrictions-on-compile-time-execution>`_ for details.
A `checked runtime error`:idx: is an error that the implementation detects The compiler parses Nim source code into an internal data structure called the
and reports at runtime. The method for reporting such errors is via *raising `abstract syntax tree`:idx: (`AST`:idx). Then, before executing the code or
exceptions* or *dying with a fatal error*. However, the implementation processing it into the executable, it transforms the AST through `semantic
provides a means to disable these runtime checks. See the section pragmas_ analysis`:idx:. This adds considerable semantic information to the AST, such as
for details. expression types, identifier meanings, and in some cases expression values. An
error detected during semantic analysis is called a `static error`:idx:. Errors
mentioned in this manual are static errors when not otherwise specified.
Whether a checked runtime error results in an exception or in a fatal error at An error detected during code execution (whether at compile time or at runtime)
runtime is implementation specific. Thus the following program is always is a `checked execution error`:idx:. The method for reporting such errors is via
invalid: *raising exceptions* or *dying with a fatal error*. However, the implementation
provides a means to disable these `execution-time checks`:idx:. See the section
pragmas_ for details.
Whether a checked execution error results in an exception or in a fatal error
is implementation specific. Thus the following program is invalid; even
though it purports to catch the `IndexError` from an out-of-bounds array access,
the compiler may instead choose to allow execution to die with a fatal error.
.. code-block:: nim .. code-block:: nim
var a: array[0..1, char] var a: array[0..1, char]
@ -95,11 +111,28 @@ invalid:
except IndexError: except IndexError:
echo "invalid index" echo "invalid index"
An `unchecked runtime error`:idx: is an error that is not guaranteed to be An `unchecked execution 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 execution errors cannot occur if only `safe`:idx:
language features are used. language features are used and if no execution-time 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 the substantial
subset of the Nim language that is supported at compile time. 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 saw just above that this interleaving is necessary for handling
constant expressions. 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
@ -673,10 +706,90 @@ 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`. This is an expression whose value can be computed during
semantic analysis of the code in which it appears. However, constant
expressions are not limited to the capabilities of semantic analysis; they
can use the substantial subset of the Nim language that is supported for
compile-time execution. Compile-time execution is interleaved with semantic
analysis as necessary. A constant's value cannot change after it is first
computed.
A constant expression must be composed of the following elements:
* literals
* 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
* operators representing such procedures
* code blocks that can internally use all Nim features supported at
compile time (the next section below), but that cannot
refer to any external values beyond those listed above
Constant expressions must adhere to the restrictions on compile-time
execution described in `Restrictions on
Compile-Time Execution <restrictions-on-compile-time-execution>`_.
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 0..10:
if i > 0:
add(result, ", ")
add(result, $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
* ``cast``
* ``ptr``s or ``ref``s
* 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.
@ -700,9 +813,9 @@ Ordinal types have the following characteristics:
the operation of functions as ``inc``, ``ord``, ``dec`` on ordinal types to the operation of functions as ``inc``, ``ord``, ``dec`` on ordinal types to
be defined. be defined.
- Ordinal values have a smallest possible value. Trying to count further - Ordinal values have a smallest possible value. Trying to count further
down than the smallest value gives a checked runtime or static error. down than the smallest value gives a checked execution or static error.
- Ordinal values have a largest possible value. Trying to count further - Ordinal values have a largest possible value. Trying to count further
than the largest value gives a checked runtime or static error. than the largest value gives a checked execution or static error.
Integers, bool, characters and enumeration types (and subranges of these Integers, bool, characters and enumeration types (and subranges of these
types) belong to ordinal types. For reasons of simplicity of implementation types) belong to ordinal types. For reasons of simplicity of implementation
@ -810,7 +923,7 @@ 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 execution error (or static error if it can be statically
determined). Assignments from the base type to one of its subrange types determined). Assignments from the base type to one of its subrange types
(and vice versa) are allowed. (and vice versa) are allowed.
@ -854,7 +967,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:.
@ -881,8 +994,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
@ -1110,8 +1224,8 @@ 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 same type. Arrays always have a fixed length which is specified at has the same type. Arrays always have a fixed length which is known during
compile time (except for open arrays). They can be indexed by any ordinal type. semantic analysis (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
@ -1119,7 +1233,7 @@ inferred from the type of the first element. All other elements need to be
implicitly convertable to this type. implicitly convertable to this type.
Sequences are similar to arrays but of dynamic length which may change Sequences are similar to arrays but of dynamic length which may change
during runtime (like strings). Sequences are implemented as growable arrays, during execution (like strings). Sequences are implemented as growable arrays,
allocating pieces of memory as items are added. A sequence ``S`` is always allocating pieces of memory as items are added. A sequence ``S`` is always
indexed by integers from 0 to ``len(S)-1`` and its bounds are checked. indexed by integers from 0 to ``len(S)-1`` and its bounds are checked.
Sequences can be constructed by the array constructor ``[]`` in conjunction Sequences can be constructed by the array constructor ``[]`` in conjunction
@ -1153,7 +1267,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 during execution). 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.
@ -1260,7 +1374,7 @@ is currently not checked.
**Future directions**: GC'ed memory should be allowed in unchecked arrays and **Future directions**: GC'ed memory should be allowed in unchecked arrays and
there should be an explicit annotation of how the GC is to determine the there should be an explicit annotation of how the GC is to determine the
runtime size of the array. execution-time size of the array.
@ -1317,7 +1431,7 @@ can also be defined with indentation instead of ``[]``:
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 information hiding. Objects have access to their type at runtime, so that and information hiding. Objects have access to their type during execution, 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`` operator
is similar to the ``instanceof`` operator in Java. is similar to the ``instanceof`` operator in Java.
@ -1415,7 +1529,7 @@ 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 correct value
for the discriminator must be supplied at compile-time. for the discriminator must be available for semantic analysis.
Package level objects Package level objects
--------------------- ---------------------
@ -1429,7 +1543,7 @@ 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 ``sizeof(T)`` or "execution-time type
information" for ``T`` is not available. information" for ``T`` is not available.
@ -1859,7 +1973,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
@ -2246,11 +2360,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
argument can match. Let ``f`` be the formal parameter's type and ``a`` the type
of the argument.
1. Exact match: ``a`` and ``f`` are of the same type. 1. Exact match: ``a`` and ``f`` are of the same type.
2. Literal match: ``a`` is an integer literal of value ``v`` 2. Literal match: ``a`` is an integer literal of value ``v``
@ -2627,53 +2738,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-compile-time-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
------------ ------------
@ -2747,9 +2841,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 computable during analysis.
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
@ -2814,10 +2908,10 @@ Example:
.. code-block:: nim .. code-block:: nim
proc someProcThatMayRunInCompileTime(): bool = proc someProcThatMayRunInCompileTime(): bool =
when nimvm: when nimvm:
# This code runs in compile time # This code executes at compile time
result = true result = true
else: else:
# This code runs in runtime # This code executes at runtime
result = false result = false
const ctValue = someProcThatMayRunInCompileTime() const ctValue = someProcThatMayRunInCompileTime()
let rtValue = someProcThatMayRunInCompileTime() let rtValue = someProcThatMayRunInCompileTime()
@ -3557,7 +3651,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
@ -3673,7 +3767,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
@ -3794,7 +3888,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.
@ -4113,7 +4207,7 @@ 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 execution error
that can be caught inherit from ``system.CatchableError`` that can be caught inherit from ``system.CatchableError``
(which is a subtype of ``Exception``). (which is a subtype of ``Exception``).
@ -4351,7 +4445,7 @@ a `type variable`:idx:.
Is operator Is operator
----------- -----------
The ``is`` operator checks for type equivalence at compile time. It is The ``is`` operator checks for type equivalence during semantic analysis. It is
therefore very useful for type specialization within generic code: therefore very useful for type specialization within generic code:
.. code-block:: nim .. code-block:: nim
@ -5357,6 +5451,14 @@ invocation would have been replaced by its result in the source
code. This can be used to implement `domain specific code. This can be used to implement `domain specific
languages`:idx:. languages`:idx:.
Macro invocation leads to a case where semantic analyis does **not** entirely
proceed top to bottom and left to right. The compiler must
* perform semantic analysis through the end of the macro invocation,
* execute the macro body,
* replace the AST of the macro invocation with the AST returned by the macro,
* and finally repeat semantic analysis of that region of the code.
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
Nim's syntax is flexible enough anyway. Nim's syntax is flexible enough anyway.
@ -5639,7 +5741,8 @@ 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 computable during
semantic analysis:
.. code-block:: nim .. code-block:: nim
@ -5651,7 +5754,8 @@ 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 computable during
# semantic analysis
For the purposes of code generation, all static params are treated as For the purposes of code generation, all static params are treated as
@ -5665,7 +5769,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]
@ -5673,13 +5777,12 @@ 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 values computable during semantic analysis. A more specific type
specific type class can be created by instantiating ``static`` with class can be created by 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 the evaluation of a certain expression during semantic analysis by
coercing it to a corresponding ``static`` type: coercing it to a corresponding ``static`` type:
.. code-block:: nim .. code-block:: nim
@ -6766,11 +6869,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 =
@ -6858,7 +6961,7 @@ 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 which is used for runtime type identification is omitted. This used to be field which is used for execution-time 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
@ -6884,7 +6987,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
@ -7006,7 +7109,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 =
@ -7039,7 +7142,7 @@ others may be added later).
=============== =============== ============================================ =============== =============== ============================================
pragma allowed values description pragma allowed values description
=============== =============== ============================================ =============== =============== ============================================
checks on|off Turns the code generation for all runtime checks on|off Turns the code generation for all execution
checks on or off. checks on or off.
boundChecks on|off Turns the code generation for array bound boundChecks on|off Turns the code generation for array bound
checks on or off. checks on or off.
@ -7066,7 +7169,7 @@ Example:
.. code-block:: nim .. code-block:: nim
{.checks: off, optimization: speed.} {.checks: off, optimization: speed.}
# compile without runtime checks and optimize for speed # compile without execution-time checks and optimize for speed
push and pop pragmas push and pop pragmas
@ -7076,7 +7179,7 @@ but are used to override the settings temporarily. Example:
.. code-block:: nim .. code-block:: nim
{.push checks: off.} {.push checks: off.}
# compile this section without runtime checks as it is # compile this section without execution-time checks as it is
# speed critical # speed critical
# ... some code ... # ... some code ...
{.pop.} # restore old settings {.pop.} # restore old settings
@ -7321,7 +7424,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").}
@ -7335,7 +7439,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").}
@ -7946,7 +8051,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
@ -8229,8 +8334,8 @@ Example:
The parallel statement is the preferred mechanism to introduce parallelism The parallel statement is the preferred mechanism to introduce parallelism
in a Nim program. A subset of the Nim language is valid within a in a Nim program. A subset of the Nim language is valid within a
``parallel`` section. This subset is checked to be free of data races at ``parallel`` section. This subset is checked to be free of data races during
compile time. A sophisticated `disjoint checker`:idx: ensures that no data semantic analysis. A sophisticated `disjoint checker`:idx: ensures that no data
races are possible even though shared memory is extensively supported! races are 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
@ -8263,8 +8368,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 static analysis.
Guards and the locks section Guards and the locks section
@ -8296,9 +8401,9 @@ Top level accesses to ``gdata`` are always allowed so that it can be initialized
conveniently. It is *assumed* (but not enforced) that every top level statement conveniently. It is *assumed* (but not enforced) that every top level statement
is executed before any concurrent action happens. is executed before any concurrent action happens.
The ``locks`` section deliberately looks ugly because it has no runtime The ``locks`` section deliberately looks ugly because it has no execution-time
semantics and should not be used directly! It should only be used in templates semantics and should not be used directly! It should only be used in templates
that also implement some form of locking at runtime: that also implement some form of locking during execution:
.. code-block:: nim .. code-block:: nim
template lock(a: TLock; body: untyped) = template lock(a: TLock; body: untyped) =
@ -8384,9 +8489,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
@ -8416,7 +8522,7 @@ single ``locks`` section:
Here is how a typical multilock statement can be implemented in Nim. Note how 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`` the execution check is required to ensure a global ordering for two locks ``a``
and ``b`` of the same lock level: and ``b`` of the same lock level:
.. code-block:: nim .. code-block:: nim