diff options
author | Araq <rumpf_a@web.de> | 2014-02-01 13:39:40 +0100 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2014-02-01 13:39:40 +0100 |
commit | 6d62503e5d8d195e3da7d9cb30782410a5d3c3ea (patch) | |
tree | 9d45451bb6dac4e810ea42d43c2424f3a5ac5f97 /doc | |
parent | d8d93218fa509b8980d5ecb4b8af4e70e9f4926e (diff) | |
download | Nim-6d62503e5d8d195e3da7d9cb30782410a5d3c3ea.tar.gz |
documented new symbol binding rules for templates
Diffstat (limited to 'doc')
-rw-r--r-- | doc/manual.txt | 131 |
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` |