It would be really nice to be able to write something like this
let a = block:
echo "hello"
1
but this does not compile because block is a statement
a trivial workaround is
let a = (proc() : auto =
echo "hello"
1
)()
which is quite ugly (and reminds me Javascript, which makes it just uglier) then I tried to write a template to keep using a beautiful syntax
template scope(body) =
let f = proc() : auto =
body
f()
let a = scope:
echo "hello"
1
but it does not work, I also tried this:
template scope(body) = (proc() : auto = body) ()
let a = scope:
echo "hello"
1
but it also fail to compile.. What is the correct way to do it?I'll answer my own question.. It seems that I just forgot to specify the template return type:
template scope(body : typed) : auto = (proc() : auto = body) ()
let a = scope:
echo "hello"
1
this works fine. There are some things that are not very clear to me about metaprogramming, it would be nice to have a more extended documentation about it. For example I see that templates can not only return an untyped value (which is just a piece of AST), but also a concrete value (in this example an integer). Is this possible also for macros (I would say no, but maybe I miss something)?I also noticed another problem
let a = (proc() : auto =
let b = 4
6
)()
echo b
this clearly does not compiles since b is accessed from an outer scope. This one should be the equivalent written with templates:
template bxpr(body : typed) : auto = (proc() : auto = body)()
let a = bxpr:
let b = 4
6
echo b
but, surprisingly, this compiles and prints 4 on stdout. But what is really funny is that, during the compilation it prints
test.nim(4, 9) Hint: 'b' is declared but not used [XDeclaredButNotUsed]
test.nim(3, 5) Hint: 'a' is declared but not used [XDeclaredButNotUsed]
XDMoral of the story, this works:
let a = (block:
echo "hello"
1)
Well... the template is the right thing to do but without closure magic --- just use a block:
template scope(code): auto =
block:
code
let a = scope:
echo "hello"
1
echo a
@Udiknedormin Thanks, you code works! Actually I was using this:
template scope(body : typed) : auto = (block: body)
but I guess ther is something I miss about the semantics of typed because this code
template scope(body : typed) : auto = (block: body)
let c = scope:
let b = 5
1
echo b
prints 5. Without the type of the template parameter the scoping works instead. I read the documentation about typed vs untyped here but this remains quite obscure to me. There should be no need for such a template, this must be a regression.
Since this PR blocks should be an expression (see corresponding issue). There is also a test case. However the test case indeed seems to fail now on devel, not sure if testament somehow ignores the test...
Update: My compiler was just outdated. This should work on devel.