Merge pull request #4420 from yglukhov/closure-scope

Added closureScope template
This commit is contained in:
Andreas Rumpf
2016-07-04 10:41:48 +02:00
committed by GitHub
4 changed files with 44 additions and 3 deletions

View File

@@ -215,6 +215,12 @@ the closure and its enclosing scope (i.e. any modifications made to them are
visible in both places). The closure environment may be allocated on the heap
or on the stack if the compiler determines that this would be safe.
Creating closures in loops
~~~~~~~~~~~~~~~~
Since closures capture local variables by reference it is often not wanted
behavior inside loop bodies. See `closureScope <system.html#closureScope>`_
for details on how to change this behavior.
Anonymous Procs
---------------
@@ -223,7 +229,7 @@ Procs can also be treated as expressions, in which case it's allowed to omit
the proc's name.
.. code-block:: nim
var cities = @["Frankfurt", "Tokyo", "New York"]
var cities = @["Frankfurt", "Tokyo", "New York", "Kyiv"]
cities.sort(proc (x,y: string): int =
cmp(x.len, y.len))

View File

@@ -3633,6 +3633,27 @@ proc `==` *(x, y: cstring): bool {.magic: "EqCString", noSideEffect,
elif x.isNil or y.isNil: result = false
else: result = strcmp(x, y) == 0
template closureScope*(body: untyped): stmt =
## Useful when creating a closure in a loop to capture local loop variables by
## their current iteration values. Example:
##
## .. code-block:: nim
## var myClosure : proc()
## # without closureScope:
## for i in 0 .. 5:
## let j = i
## if j == 3:
## myClosure = proc() = echo j
## myClosure() # outputs 5. `j` is changed after closure creation
## # with closureScope:
## for i in 0 .. 5:
## closureScope: # Everything in this scope is locked after closure creation
## let j = i
## if j == 3:
## myClosure = proc() = echo j
## myClosure() # outputs 3
(proc() = body)()
{.pop.} #{.push warning[GcMem]: off, warning[Uninit]: off.}
when defined(nimconfig):

View File

@@ -1 +1,4 @@
discard """
output: ""
"""
import "../template/utemplates", "../closure/uclosures"

View File

@@ -1,12 +1,23 @@
# This test is included from within tunittests
import unittest
test "loop variables are captured by copy":
test "loop variables are captured by ref":
var funcs: seq[proc (): int {.closure.}] = @[]
for i in 0..10:
let ii = i
funcs.add do -> int: return ii * ii
check funcs[0]() == 100
check funcs[3]() == 100
test "loop variables in closureScope are captured by copy":
var funcs: seq[proc (): int {.closure.}] = @[]
for i in 0..10:
closureScope:
let ii = i
funcs.add do -> int: return ii * ii
check funcs[0]() == 0
check funcs[3]() == 9