I'm still getting confused about the do notation. In particular I'm surprised that the following gives an error "redefinition of x":
import future
proc takesFunc(f: () -> void) =
f()
takesFunc do:
var x = 1
takesFunc do:
var x = 1
The manual mentions something that do without parenthesis is just a block. I don't understand that, what is the compiler passing to the function in this case?
Adding some empty parentheses after the do solves the problem, but if the version without the parentheses is not creating an anonymous proc, shouldn't this lead to a more meaningful error? Otherwise finding such a bug is a bit by chance like in my case with the redefinition.
The code tries to pass a parameter with the wrong type to that proc, yes. But the compiler doesn't even get that far:
I'm not sure about that. So with having just one body or no conflicts you would expect a type error? But this compiles and works just fine:
import future
proc takesFunc(f: () -> void) =
echo "running f()"
f()
echo "done running f()"
takesFunc do:
var x = 1
echo x
takesFunc do:
var y = 2
echo y
Output:
running f()
1
done running f()
running f()
2
done running f()
I tested with 0.16.1. With current 0.17.1 indeed the last example compiles, and the first fails with redifinition. So now do means something different, I don't know what. May be a bug, maybe a special case of blocks with no new scope. Otherwise blocks open new scopes, and this for example did compile and still does now:
block:
var x = 1
echo x
block:
var x = 2
echo x
I tested with 0.16.1. With current 0.17.1
I used 0.17.0 (stable), same behavior. So now we now what Nim does here:
The second point is corroborated by the fact that bluenote's first example does compile when I add explicit block statements to force a scope.
import future
proc takesFunc(f: () -> void) =
f()
takesFunc do:
block:
var x = 1
takesFunc do:
block:
var x = 1
And I really don't like that. If it becomes a procedure, making its body a scope would seem more intuitive to me.
By the way, there seem to be two different ideas of "block" in Nim, an unscoped and a scoped one. See the manual section "Passing a code block to a template". The whole typed vs untyped thing only makes sense when blocks without an explicit block statement are unscoped.
Most likely this is not really intended. For instance, this now compiles, but produces invalid C code:
import future
proc takesFunc(f: () -> void) =
f()
takesFunc do:
var x = 1
echo x
Probably best to track this as an issue: https://github.com/nim-lang/Nim/issues/5963