-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Open
Labels
Description
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 :
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.