summary refs log tree commit diff stats
path: root/doc
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2014-02-01 13:39:40 +0100
committerAraq <rumpf_a@web.de>2014-02-01 13:39:40 +0100
commit6d62503e5d8d195e3da7d9cb30782410a5d3c3ea (patch)
tree9d45451bb6dac4e810ea42d43c2424f3a5ac5f97 /doc
parentd8d93218fa509b8980d5ecb4b8af4e70e9f4926e (diff)
downloadNim-6d62503e5d8d195e3da7d9cb30782410a5d3c3ea.tar.gz
documented new symbol binding rules for templates
Diffstat (limited to 'doc')
-rw-r--r--doc/manual.txt131
1 files changed, 59 insertions, 72 deletions
diff --git a/doc/manual.txt b/doc/manual.txt
index faf62dcee..260f0807a 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -12,6 +12,8 @@ Nimrod Manual
   user to one/some of the other players, but the total amount seems to remain
   pretty much constant for a given task. -- Ran
 
+
+
 About this document
 ===================
 
@@ -1479,7 +1481,7 @@ But it seems all this boilerplate code needs to be repeated for the ``TEuro``
 currency. This can be solved with templates_.
 
 .. code-block:: nimrod
-  template Additive(typ: typedesc): stmt =
+  template additive(typ: typedesc): stmt =
     proc `+` *(x, y: typ): typ {.borrow.}
     proc `-` *(x, y: typ): typ {.borrow.}
     
@@ -1487,26 +1489,26 @@ currency. This can be solved with templates_.
     proc `+` *(x: typ): typ {.borrow.}
     proc `-` *(x: typ): typ {.borrow.}
 
-  template Multiplicative(typ, base: typedesc): stmt =
+  template multiplicative(typ, base: typedesc): stmt =
     proc `*` *(x: typ, y: base): typ {.borrow.}
     proc `*` *(x: base, y: typ): typ {.borrow.}
     proc `div` *(x: typ, y: base): typ {.borrow.}
     proc `mod` *(x: typ, y: base): typ {.borrow.}
 
-  template Comparable(typ: typedesc): stmt =
+  template comparable(typ: typedesc): stmt =
     proc `<` * (x, y: typ): bool {.borrow.}
     proc `<=` * (x, y: typ): bool {.borrow.}
     proc `==` * (x, y: typ): bool {.borrow.}
 
-  template DefineCurrency(typ, base: expr): stmt =
+  template defineCurrency(typ, base: expr): stmt =
     type
       typ* = distinct base
-    Additive(typ)
-    Multiplicative(typ, base)
-    Comparable(typ)
+    additive(typ)
+    multiplicative(typ, base)
+    comparable(typ)
     
-  DefineCurrency(TDollar, int)
-  DefineCurrency(TEuro, int)
+  defineCurrency(TDollar, int)
+  defineCurrency(TEuro, int)
 
 
 Void type
@@ -3440,13 +3442,41 @@ A symbol can be forced to be open by a `mixin`:idx: declaration:
 
 .. code-block:: nimrod
   proc create*[T](): ref T =
-    # there is no overloaded 'mixin' here, so we need to state that it's an
+    # there is no overloaded 'init' here, so we need to state that it's an
     # open symbol explicitly:
     mixin init
     new result
     init result
 
 
+Bind statement
+--------------
+
+The `bind`:idx: statement is the counterpart to the ``mixin`` statement. It 
+can be used to explicitly declare identifiers that should be bound early (i.e.
+the identifiers should be looked up in the scope of the template/generic
+definition):
+
+.. code-block:: nimrod
+  # Module A
+  var 
+    lastId = 0
+  
+  template genId*: expr =
+    bind lastId
+    inc(lastId)
+    lastId
+
+.. code-block:: nimrod
+  # Module B
+  import A
+  
+  echo genId()
+
+But a ``bind`` is rarely useful because symbol binding from the definition
+scope is the default.
+
+
 Templates
 =========
 
@@ -3506,28 +3536,6 @@ receive undeclared identifiers:
   declareInt(x) # valid
 
 
-Scoping in templates
---------------------
-
-The template body does not open a new scope. To open a new scope a ``block``
-statement can be used:
-
-.. code-block:: nimrod
-  template declareInScope(x: expr, t: typedesc): stmt {.immediate.} = 
-    var x: t
-    
-  template declareInNewScope(x: expr, t: typedesc): stmt {.immediate.} = 
-    # open a new scope:
-    block: 
-      var x: t
-
-  declareInScope(a, int)
-  a = 42  # works, `a` is known here
-  
-  declareInNewScope(b, int)
-  b = 42  # does not work, `b` is unknown
-
-
 Passing a code block to a template
 ----------------------------------
 
@@ -3538,50 +3546,28 @@ special ``:`` syntax:
 .. code-block:: nimrod
 
   template withFile(f, fn, mode: expr, actions: stmt): stmt {.immediate.} =
-    block:
-      var f: TFile
-      if open(f, fn, mode):
-        try:
-          actions
-        finally:
-          close(f)
-      else:
-        quit("cannot open: " & fn)
+    var f: TFile
+    if open(f, fn, mode):
+      try:
+        actions
+      finally:
+        close(f)
+    else:
+      quit("cannot open: " & fn)
       
   withFile(txt, "ttempl3.txt", fmWrite):
     txt.writeln("line 1")
     txt.writeln("line 2")
   
 In the example the two ``writeln`` statements are bound to the ``actions``
-parameter. 
-
-**Note:** The symbol binding rules for templates might change!
-
-Symbol binding within templates happens after template instantiation: 
-
-.. code-block:: nimrod
-  # Module A
-  var 
-    lastId = 0
-  
-  template genId*: expr =
-    inc(lastId)
-    lastId
-
-.. code-block:: nimrod
-  # Module B
-  import A
-  
-  echo genId() # Error: undeclared identifier: 'lastId'
+parameter.
 
 
-Bind statement
---------------
+Symbol binding in templates
+---------------------------
 
-Exporting a template is a often a leaky abstraction as it can depend on 
-symbols that are not visible from a client module. However, to compensate for
-this case, a `bind`:idx: statement can be used: It declares all identifiers
-that should be bound early (i.e. when the template is parsed):
+A template is a `hygienic`:idx: macro and so opens a new scope. Most symbols are
+bound from the definition scope of the template:
 
 .. code-block:: nimrod
   # Module A
@@ -3589,7 +3575,6 @@ that should be bound early (i.e. when the template is parsed):
     lastId = 0
   
   template genId*: expr =
-    bind lastId
     inc(lastId)
     lastId
 
@@ -3597,9 +3582,11 @@ that should be bound early (i.e. when the template is parsed):
   # Module B
   import A
   
-  echo genId() # Works
+  echo genId() # Works as 'lastId' has been bound in 'genId's defining scope
+
+As in generics symbol binding can be influenced via ``mixin`` or ``bind`` 
+statements.
 
-A ``bind`` statement can also be used in generics for the same purpose.
 
 
 Identifier construction
@@ -3942,13 +3929,13 @@ Static params can also appear in the signatures of generic types:
 
   type
     Matrix[M,N: static[int]; T: Number] = array[0..(M*N - 1), T]
-      # Please, 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
 
     AffineTransform2D[T] = Matrix[3, 3, T]
     AffineTransform3D[T] = Matrix[4, 4, T]
 
-  AffineTransform3D[float] # OK
+  AffineTransform3D[float]  # OK
   AffineTransform2D[string] # Error, `string` is not a `Number`