Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula. Its design focuses on efficiency, expressiveness, and elegance (in that order of priority).
There can be multiple scopes inside a same functions thanks to blocks and templates. But this scope aren't captured as is when creating a closure. This can result in pointing to the wrong variable inside the closure.
I think an example will be more explicit :
type MyRef = ref object
var myClosures: seq[proc()]
echo "DECEPTIVE EXAMPLE - with template"
template generateClosure(): proc() =
let myRef = MyRef()
echo "OUTSIDE:", cast[int](myRef)
proc closure() =
echo "INSIDE:", cast[int](myRef)
closure
for i in 0..<2:
myClosures.add generateClosure()
for p in myClosures:
p()
myClosures.setLen(0)
echo "DECEPTIVE EXAMPLE - direct substitution"
for i in 0..<2:
myClosures.add block:
let myRef = MyRef()
echo "OUTSIDE:", cast[int](myRef)
proc closure() =
echo "INSIDE:", cast[int](myRef)
closure
for p in myClosures:
p()
myClosures.setLen(0)
echo "WORKING EXAMPLE"
for i in 0..<2:
myClosures.add block:
proc closureGenerator(): proc() =
let myRef = MyRef()
echo "OUTSIDE:", cast[int](myRef)
proc closure() =
echo "INSIDE:", cast[int](myRef)
closure
closureGenerator()
for p in myClosures:
p()
Nim Version
On fedora, v2.0.4
Current Output
DECEPTIVE EXAMPLE - with template
OUTSIDE:139977855484000
OUTSIDE:139977855484096
INSIDE:139977855484096
INSIDE:139977855484096
DECEPTIVE EXAMPLE - direct subsitution
OUTSIDE:139977855484064
OUTSIDE:139977855484192
INSIDE:139977855484192
INSIDE:139977855484192
WORKING EXAMPLE
OUTSIDE:139977855484256
OUTSIDE:139977855484288
INSIDE:139977855484256
INSIDE:139977855484288
Possible Solution
I'm not sure if it is possible to capture a nested scope correctly (blocks/templates) without implying a closure. So I don't think a correction is possible without overhead or breaking how nim actually works.
However, it might certainly be possible for the compiler to detect when a referenced scope will be erased and should emit a warning or an error.
Description
Hello,
There can be multiple scopes inside a same functions thanks to blocks and templates. But this scope aren't captured as is when creating a closure. This can result in pointing to the wrong variable inside the closure.
I think an example will be more explicit :
Nim Version
On fedora, v2.0.4
Current Output
Possible Solution
I'm not sure if it is possible to capture a nested scope correctly (blocks/templates) without implying a closure. So I don't think a correction is possible without overhead or breaking how nim actually works.
However, it might certainly be possible for the compiler to detect when a referenced scope will be erased and should emit a warning or an error.