documented untyped/typed meta-types

This commit is contained in:
Araq 2015-11-10 22:51:03 +01:00
commit f9ad735e55
2 changed files with 93 additions and 27 deletions

View file

@ -152,9 +152,11 @@ In module related statements, if any part of the module name /
path begins with a number, you may have to quote it in double quotes. path begins with a number, you may have to quote it in double quotes.
In the following example, it would be seen as a literal number '3.0' of type In the following example, it would be seen as a literal number '3.0' of type
'float64' if not quoted, if uncertain - quote it: 'float64' if not quoted, if uncertain - quote it:
.. code-block:: nim .. code-block:: nim
import "gfx/3d/somemodule" import "gfx/3d/somemodule"
Scope rules Scope rules
----------- -----------
Identifiers are valid from the point of their declaration until the end of Identifiers are valid from the point of their declaration until the end of

View file

@ -10,7 +10,7 @@ The syntax to *invoke* a template is the same as calling a procedure.
Example: Example:
.. code-block:: nim .. code-block:: nim
template `!=` (a, b: expr): expr = template `!=` (a, b: untyped): untyped =
# this definition exists in the System module # this definition exists in the System module
not (a == b) not (a == b)
@ -23,50 +23,56 @@ templates:
| ``a in b`` is transformed into ``contains(b, a)``. | ``a in b`` is transformed into ``contains(b, a)``.
| ``notin`` and ``isnot`` have the obvious meanings. | ``notin`` and ``isnot`` have the obvious meanings.
The "types" of templates can be the symbols ``expr`` (stands for *expression*), The "types" of templates can be the symbols ``untyped``,
``stmt`` (stands for *statement*) or ``typedesc`` (stands for *type ``typed`` or ``typedesc`` (stands for *type
description*). These are "meta types", they can only be used in certain description*). These are "meta types", they can only be used in certain
contexts. Real types can be used too; this implies that expressions are contexts. Real types can be used too; this implies that ``typed`` expressions
expected. are expected.
Ordinary vs immediate templates Typed vs untyped parameters
------------------------------- ---------------------------
There are two different kinds of templates: immediate templates and An ``untyped`` parameter means that symbol lookups and type resolution is not
ordinary templates. Ordinary templates take part in overloading resolution. As performed before the expression is passed to the template. This means that for
such their arguments need to be type checked before the template is invoked. example *undeclared* identifiers can be passed to the template:
So ordinary templates cannot receive undeclared identifiers:
.. code-block:: nim .. code-block:: nim
template declareInt(x: expr) = template declareInt(x: untyped) =
var x: int
declareInt(x) # error: unknown identifier: 'x'
An ``immediate`` template does not participate in overload resolution and so
its arguments are not checked for semantics before invocation. So they can
receive undeclared identifiers:
.. code-block:: nim
template declareInt(x: expr) {.immediate.} =
var x: int var x: int
declareInt(x) # valid declareInt(x) # valid
x = 3
.. code-block:: nim
template declareInt(x: typed) =
var x: int
declareInt(x) # invalid, because x has not been declared and so has no type
A template where every parameter is ``untyped`` is called an `immediate`:idx:
template. For historical reasons templates can be explicitly annotated with
an ``immediate`` pragma and then these templates do not take part in
overloading resolution and the parameters' types are *ignored* by the
compiler. Explicit immediate templates are about to be deprecated in later
versions of the compiler.
**Note**: For historical reasons ``stmt`` is an alias for ``typed`` and
``expr`` an alias for ``untyped``, but new code should use the newer,
clearer names.
Passing a code block to a template Passing a code block to a template
---------------------------------- ----------------------------------
If there is a ``stmt`` parameter it should be the last in the template You can pass a block of statements as a last parameter to a template via a
declaration, because statements are passed to a template via a
special ``:`` syntax: special ``:`` syntax:
.. code-block:: nim .. code-block:: nim
template withFile(f, fn, mode, actions: untyped): untyped =
template withFile(f, fn, mode: expr, actions: stmt): stmt {.immediate.} =
var f: File var f: File
if open(f, fn, mode): if open(f, fn, mode):
try: try:
@ -84,6 +90,64 @@ In the example the two ``writeLine`` statements are bound to the ``actions``
parameter. parameter.
Usually to pass a block of code to a template the parameter that accepts
the block needs to be of type ``untyped``. Because symbol lookups are then
delayed until template instantiation time:
.. code-block:: nim
template t(body: typed) =
block:
body
t:
var i = 1
echo i
t:
var i = 2 # fails with 'attempt to redeclare i'
echo i
The above code fails with the mysterious error message that ``i`` has already
been declared. The reason for this is that the ``var i = ...`` bodies need to
be type-checked before they are passed to the ``body`` parameter and type
checking in Nim implies symbol lookups. For the symbol lookups to succeed
``i`` needs to be added to the current (i.e. outer) scope. After type checking
these additions to the symbol table are not rolled back (for better or worse).
The same code works with ``untyped`` as the passed body is not required to be
type-checked:
.. code-block:: nim
template t(body: untyped) =
block:
body
t:
var i = 1
echo i
t:
var i = 2 # compiles
echo i
Varargs of untyped
------------------
In addition to the ``untyped`` meta-type that prevents type checking there is
also ``varargs[untyped]`` so that not even the number of parameters is fixed:
.. code-block:: nim
template hideIdentifiers(x: varargs[untyped]) = discard
hideIdentifiers(undeclared1, undeclared2)
However, since a template cannot iterate over varargs, this feature is
generally much more useful for macros.
**Note**: For historical reasons ``varargs[expr]`` is not equivalent
to ``varargs[untyped]``.
Symbol binding in templates Symbol binding in templates
--------------------------- ---------------------------