| We just switched from Rust to Nim for a very large proprietary project I've been involved with after rejecting proofs of concept in Go and Erlang earlier in the process. This despite the fact that we had formally decided on Rust, had tons of code developed in it, and only stumbled upon Nim by complete accident randomly one day. Even though many large components were already developed in Rust we have already reached par and have shot ahead of where we were at. I don't want to diss Rust in any way (or Go for that matter), but I figure they both have corporate backing and can easily speak for themselves, whereas Nim does not- so I don't feel too bad offering our somewhat informed opinion :-) In a nutshell, Go ended up not really being a systems language and Rust has the beautiful goal of memory safety and correctness without garbage collection but in the end feels like it's designed by committee. Nim, with Araq it's benevolent dictator, has had the opportunity to be highly opinionated. Much of the time that seems to simply allow projects to either shoot themselves in the foot or stagnate, but occasionally it produces true gems- and I really feel like that's what Nim is. Some aspects of Nim that keep blowing me away more and more: * Truly allows you to be close to the metal/OS/libraries (most beautiful and simple ffi ever) AND simultaneously allows you to think about the problem at hand in terms of the problem- i.e., high level abstractions and DSL creation like you can do with Ruby (but even cleaner in many ways). I always thought those were two opposite ends of a spectrum and didn't expect a language to even attempt to bridge the chasm- then along comes Nim and not only attempts but succeeds beyond what I ever would have thought possible. To illustrate: it has become my go-to language for quick scripting, faster to whip something together than shell or ruby or perl (and many orders of magnitude faster to run- often even including the automatic compilation the first time)- while also being the fastest, cleanest, safest way to do something low-level, like a mmapped memory-mirrored super-fast circular buffer or cpu-cache optimized lock-free message passing... * Even though it has C as an intermediate step, it doesn't feel or act anything like C. While not as strong as Rust in this area (I know, Rust goes straight to LLVM's IR instead of C- but the risks are the same)- it generates code that is much more safe (and concise) than writing it straight in C. I know, there are other language that do this well also- but usually by sacrificing the ability to easily and cleanly do system-level coding- like a raw OS system call, for example. * On a related note, despite feeling more high level than Rust, it can do so much more at a low level. For example, using musl instead of glibc (which at least last time I checked wasn't possible in Rust due to some accidental coupling). * So fast. While premature optimization is considered the root of all evil, and linear optimization often does not end up adding significant real value, I've been reminded more in the last few weeks than ever before that when speedups are around 2+ orders of magnitude _it is often a complete game changer_- it often allows you to model the problem in a completely new way (don't have a generally understandable example for Nim offhand but take docker vs dual-boot for an extreme non-Nim example- VMs were a mostly linear improvement over dual-booting and other network-based workarounds, but only with linux containers and their orders-of-magnitude "startup" time, snapshotting, etc. etc. was docker able to say "these are so cheap and fast we can assume a single running process per 'image'"). * Even though it's not as formally safe as Rust yet, in practice it feels and acts as safe, without the cognitive overload. * Rust gets tons of new commits from tons of contributors every day. I worried when looking at Nim that the lower volume of commits meant that the language was less... alive or long-term-tenable. But on closer evaluation I realized that there was literally less that needed changing, and that the changes that seemed to need code to change all over the Rust repository would, given an equivalent scope in Nim, require trivial changes to just one or two files. (for example, Rust's massive [and extremely slow] bootstrapping pipeline and parsing architecture, vs Nim's built in PEG syntax and 5-line loop that keeps compiling itself using the last iterations' outputs until the outputs don't change anymore). In short: - All the simple beauty (IMO) and conciseness of a python-like/pseudocode-like syntax without all the plumbing and pedantic one-way that comes with python. In other words, beats python at python's own strengths (not even mentioning speed or language features etc...) - Top-down modeling and DSL affinity like Ruby with less feeling of magic- e.g., better "grep"-ability and tracing. In fact, the DSLs and up being cleaner than idiomatic Ruby ones. So beats Ruby IMO at one of Ruby's core strengths. - Seems as safe as Rust with much cleaner syntax and simpler semantics. (this is something we're actively quantifying at the moment). Easily 10x the productivity. _Almost_ beats Rust at its core strength. - Easiest FFI integration of any language I've worked with, including possibly C/C++. - All the low-level facilities of C/C++ without the undefined-behavior, with better static checking, much better meta-programming, etc. etc. Beats C/C++ at their core strength. - Utterly intuitive obliteration of autotools/configure/makefile/directives type toolchains required for system development using C/C++. - It's very fast and efficient per-thread garbage-collection (when you want it) essentially allows it to eat Go and Java's lunch as well. - It's a genuinely fun language (for us at least). I've already been too verbose and am out of time but I should include for some sense of completeness some current weaknesses of Nim. None of these ended up being remotely show-stoppers for us, but at least initially we worried about: * Too much attention to windows (doing nix and even linux-only development is so easy it has turned out to be a non-issue). Less safety than Rust when doing manual memory management (hasn't been an issue and we believe unlikely to be an issue in practice). * Lack of (implied) long-term corporate support (already more stable than some others and community is strong where it counts. Also, no matter how much corporate support they get- Rust will still be more verbose and designed by committee and Go will still fall short of being a true to-the-metal systems programming language and neither will ever have Ruby and Lisp's moldability and endless potential to get out of your way). * Smaller community/package ecosystem than many others (so easy to do FFI or to even _reimplement something done in C using 1/5 the code_ that it also has turned out to be a non-issue. Now I worry that it's so easy to code that it will have a library-bloat issue like Ruby requiring something like ruby-toolbox) * "How have I not heard about this before?? Why isn't it bigger? Is something wrong with it?" I start worrying about things like D's standard-library wars or lisp & scheme's utter flexibility combined with poor readability... Nope, just new and only spread through word-of-mouth, like Ruby, Python, and Perl long ago... [there, once I've written three separate lists in a single comment I can safely say I've said too much and should get back to work]. |
> Less safety than Rust when doing manual memory management (hasn't been an issue and we believe unlikely to be an issue in practice).
One major safety issue with Nim is that sending garbage collected pointers between threads will segfault, last I checked (unless you use the Boehm GC). Moreover, Nim is essentially entirely GC'd if you want (thread-local) safety; there is no safety when not using the GC. So Nim is in a completely different category from Rust; Rust's "core strength" is memory safety without garbage collection, which Nim (or any other industry language, save perhaps ATS) does not provide at all.