summary refs log tree commit diff stats
path: root/doc/manual
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2015-11-10 22:51:03 +0100
committerAraq <rumpf_a@web.de>2015-11-10 22:51:03 +0100
commitf9ad735e55d45d6a3ed7e9e7da7abd31065f99ac (patch)
treec046a9ba8e20e6b5239373bae1c6f588761d4349 /doc/manual
parentb6374f1f68d899e7eed65c553f3e8b71e688c61c (diff)
downloadNim-f9ad735e55d45d6a3ed7e9e7da7abd31065f99ac.tar.gz
documented untyped/typed meta-types
Diffstat (limited to 'doc/manual')
-rw-r--r--doc/manual/modules.txt2
-rw-r--r--doc/manual/templates.txt108
2 files changed, 88 insertions, 22 deletions
diff --git a/doc/manual/modules.txt b/doc/manual/modules.txt
index e6a08b5ce..ac47d89dd 100644
--- a/doc/manual/modules.txt
+++ b/doc/manual/modules.txt
@@ -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.
 In the following example, it would be seen as a literal number '3.0' of type
 'float64' if not quoted, if uncertain - quote it:
+
 .. code-block:: nim
   import "gfx/3d/somemodule"
 
+
 Scope rules
 -----------
 Identifiers are valid from the point of their declaration until the end of
diff --git a/doc/manual/templates.txt b/doc/manual/templates.txt
index 092d65ea2..b60fe632e 100644
--- a/doc/manual/templates.txt
+++ b/doc/manual/templates.txt
@@ -10,7 +10,7 @@ The syntax to *invoke* a template is the same as calling a procedure.
 Example:
 
 .. code-block:: nim
-  template `!=` (a, b: expr): expr =
+  template `!=` (a, b: untyped): untyped =
     # this definition exists in the System module
     not (a == b)
 
@@ -23,50 +23,56 @@ templates:
 | ``a in b`` is transformed into ``contains(b, a)``.
 | ``notin`` and ``isnot`` have the obvious meanings.
 
-The "types" of templates can be the symbols ``expr`` (stands for *expression*),
-``stmt`` (stands for *statement*) or ``typedesc`` (stands for *type
+The "types" of templates can be the symbols ``untyped``,
+``typed`` or ``typedesc`` (stands for *type
 description*). These are "meta types", they can only be used in certain
-contexts. Real types can be used too; this implies that expressions are
-expected.
+contexts. Real types can be used too; this implies that ``typed`` expressions
+are expected.
 
 
-Ordinary vs immediate templates
--------------------------------
+Typed vs untyped parameters
+---------------------------
 
-There are two different kinds of templates: immediate templates and
-ordinary templates. Ordinary templates take part in overloading resolution. As
-such their arguments need to be type checked before the template is invoked.
-So ordinary templates cannot receive undeclared identifiers:
+An ``untyped`` parameter means that symbol lookups and type resolution is not
+performed before the expression is passed to the template. This means that for
+example *undeclared* identifiers can be passed to the template:
 
 .. code-block:: nim
 
-  template declareInt(x: expr) =
+  template declareInt(x: untyped) =
     var x: int
 
-  declareInt(x) # error: unknown identifier: 'x'
+  declareInt(x) # valid
+  x = 3
 
-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.} =
+  template declareInt(x: typed) =
     var x: int
 
-  declareInt(x) # valid
+  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
 ----------------------------------
 
-If there is a ``stmt`` parameter it should be the last in the template
-declaration, because statements are passed to a template via a
+You can pass a block of statements as a last parameter to a template via a
 special ``:`` syntax:
 
 .. code-block:: nim
-
-  template withFile(f, fn, mode: expr, actions: stmt): stmt {.immediate.} =
+  template withFile(f, fn, mode, actions: untyped): untyped =
     var f: File
     if open(f, fn, mode):
       try:
@@ -84,6 +90,64 @@ In the example the two ``writeLine`` statements are bound to the ``actions``
 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
 ---------------------------