5 ms·
Interesting that Nim (lang) is used in the examples- good readable code too
by jadbox 10y ago
Interesting that Nim (lang) is used in the examples- good readable code too
- qwertyuiop924 10y agoYeah, Nim is interesting, and pretty nice for gamedev (efficient, GCed when you want it, hand management when you don't, no stop-the-world, etc.). Personally, I haven't worked with it much yet, as there are just too many languages, and some of the semantics were immidiate turn-offs (static typing with very minimal inference, odd multi-assignment semantics, enforced use of discard (which discourages minimal APIs, and encourages functions with side-effects to have no return value, which is a Bad Thing), requiring forward declarations (if you need it for metaprogramming, than why can Scheme and Lisp avoid it?), not defaulting to bignums, dynamic dispatch chosen by the creator of the original class, really clumsy macros, no hygene AFAICT (although two namespaces and a module system make this less of an issue: However, I doubt the module system was built to protect hygene. Somebody should look into this, so we can know for sure), really, really clumsy macros (I mean really, come on guys: macros aren't new: how did you even mess that up? You can totally do better than that, even without parens. But if you add parens, it's so much easier. Clojure even made it socially acceptable!)).
- perturbation 10y agoCould you expand on the lack of hygiene? I know Nim has hygienic templates by default, with an opt for 'injecting' variables into the enclosing scope (which comes in handy when (for example) you have a DSL for parsing command line options like the docopt.nim or commandeer packages). 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.
- qwertyuiop924 10y agoI meant that ASTs were non-hygenic, with all the problems therein, and nary a gensym to be seem, AFAICT. 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.
- dom96 10y ago> ... and nary a gensym to be seem ... You mean this? http://nim-lang.org/docs/macros.html#genSym,NimSymKind,string http://nim-lang.org/docs/macros.html#genSym,NimSymKind,strin...
- qwertyuiop924 10y agoAh, there it is. Thanks. That makes things a little bit better, but still.
- astrange 10y agoDefaulting to bignums would turn every + in the program from O(1) to O(N). That makes secure programming pretty difficult - this attack's already bad enough: http://arstechnica.com/business/2011/12/huge-portions-of-web-vulnerable-to-hashing-denial-of-service-attack/ http://arstechnica.com/business/2011/12/huge-portions-of-web...
- qwertyuiop924 10y agoIt's that, or have every + risk integer overflow. 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...
- astrange 10y agoI really recommend having the program trap on overflow. There are some proposals like as-if-infinitely-ranged, which is like bignums but without having to actually store a bignum. 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.
- qwertyuiop924 10y agoC actually makes it really hard to trap on overflow. It's one of the biggest reasons C kinda sucks. The way a lot of HLLs do it is to detect a potential overflow, and convert to bignum if needed.
- dom96 10y agoI agree with a lot of your points, and I can assure you that many of them are on our to do list including removal of the need for forward declarations. However, I very much disagree with your assessment of Nim's macros, what exactly makes them "really really clumsy?" 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/httpclient.nim#L897 https://github.com/nim-lang/Nim/blob/devel/lib/pure/httpclie... 2: https://github.com/nim-lang/Nim/blob/devel/lib/pure/asyncmacro.nim#L374-L480 https://github.com/nim-lang/Nim/blob/devel/lib/pure/asyncmac...
- qwertyuiop924 10y agoOf course they're powerful. They're true imperative macros, the very thing that all Smug Lisp Weenies worship (I don't, because I'm not an SLW, but they are Pretty Cool). The reason I think the macros are clumsy is pretty simple: Nim is really, really bad at manipulating its own AST: It shuffles around, munging data, and by the end, you have no idea what the result should look like. Unlike Lisp, there are no templates in macros, which make seeing what the result will be very easy. 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.
- johnnovak 10y agoYeah, Nim is my favourite language currently! The expressivity and succinctness of Python with the speed of C, plus useful metaprogramming constructs. I recommend everyone to give it a go!