If you mean that whatever AST is generated by calling macro gets put in the enclosing scope - then yes, AFAIK you're right, but this can be fixed by wrapping a macro in a proc (function).
I'll agree that forward declaration is really clumsy, I hope that that is fixed before 1.0.
That's pretty bad.
I also fail to see how wrapping a macro in a proc would help, unless you mean the call to the macro at the expansion site, which is a pretty clumsy thing to do, and actually doesn't fix most of the problems.
You mean this? http://nim-lang.org/docs/macros.html#genSym,NimSymKind,strin...
That makes things a little bit better, but still.
http://arstechnica.com/business/2011/12/huge-portions-of-web...
It's a small thing, but it's nice to do. Or at least detect overflows and move to bignum in the default numerical implementation. It's not end-of-the-world if you don't, but it helps avoid a lot of bugs...
It's really problematic to use them, though. Every integer would turn into a pointer, and the O(N) thing really is a problem. If you're doing secure coding you need careful control of data dependencies, since they create side-channel leaks, and nobody who makes "safe" languages appreciates this.
Plus most people don't need numbers that big. I think it was even a mistake to make size_t 64-bit.
The way a lot of HLLs do it is to detect a potential overflow, and convert to bignum if needed.
I have worked with them a lot and they are very powerful (if a bit verbose), despite this I was able to write a fairly nice implementation of async await and just last weekend I made writing both synchronous and asynchronous IO code much easier using a ``multisync`` macro[1]. This only took me ~100 lines[2].
1: Still a WIP, but already reduces code duplication A LOT: https://github.com/nim-lang/Nim/blob/devel/lib/pure/httpclie...
2: https://github.com/nim-lang/Nim/blob/devel/lib/pure/asyncmac...
This is how a debug macro, a very simple one, is implemented in Nim (taken from the tutorial):
macro debug(n: varargs[expr]): stmt =
result = newNimNode(nnkStmtList, n)
for i in 0..n.len-1:
result.add(newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
result.add(newCall("write", newIdentNode("stdout"), newStrLitNode(": ")))
result.add(newCall("writeLine", newIdentNode("stdout"), n[i]))
What the heck is going on? This is the equivalent Lisp (specifically, Chicken Scheme, the dialect I am most familiar with, but it should be similar in most lisps with imperative macros): (define-syntax debug
(ir-macro-transformer
(lambda (e i c)
(let ((stmts (cdr e)))
(map (lambda (stmt)
`(begin (write ,stmt)
(display ": ")
(newline))
stmts)))))
That's much easier to understand. It might be a bit less concise, but it more than makes up for it.I don't blame Nim for being bad at manipulating its own AST. Lisp is pretty bad at it, too (no, lists are not the lisp AST, not in any lisp suitable for the Real World. I don't know who told you that, but it's a lie: Most lisp ASTs are just as complex as Nim's). What I do blame Nim for is not being potentially homoiconic so there's no easy datastructure to represent code in, or at least providing a datastructure that's easier to manipulate, or at the very least provide some mechanisms to make the existing structures easier to manipulate.
(define-syntax debug
(ir-macro-transformer
(lambda (e i c)
(let ((stmts (cdr e)))
(cons 'begin (map (lambda (stmt)
`(begin (write ,stmt)
(display ": ")
(newline))
stmts)))))