Pros and Cons of Nim(onlinetechinfo.com) |
Pros and Cons of Nim(onlinetechinfo.com) |
- It has a bus/lottery factor of 1. The vast majority of all the changes were done by Araq and I have very little faith that the language would survive without him. This is even more pronounced with Zig (mentioned in comments here).
- It has had some very embarrassing bugs after the 1.0 milestone. Most of them were specific to Windows (e.g. [0]), which casts a lot of doubt on its cross-platform promise. Multiple times in the last year, when debugging a nim program, it turned out that the problem was in the language/standard library.
Now, these might not be reasons enough to not use nim, since it's a lovely language when it works, but a pro/con list should be honest.
And with respect to the ecosystem-at-large, there are tens of contributors and a very healthy package repository: nimble (package manager) written and maintained by dom96; arraymancer (tensor+array+nn) written and maintained by mratsim; an up-and-coming thread runtime by mratsim (called weave) which is better than just about any existing thread runtime for any language. NimPy for seamless python integration (... which produces one DLL that works with every Python version; can your C++ do that?) by yglukov, and many more.
And most libraries you'd need already have a Nim wrapper, (and one is extremely easy to generate if not), though the pure-nim body is growing every day - have a look at https://nimble.directory/
What was Rusts early years like? Was it one developer for the first part?
I'd imagine this is not a big deal in the early days, where the benevolent dictator is as much the language as the project itself, not all technology adoption happens on the same timelines. Matz with Ruby took a long time to become super popular, Rich Hickey with Clojure seemed to be a powerhouse even as that found quick adoption before stalling.
When Rust started as a hobby project it was a one man effort, but it was also a project with ~1 user. It grew developers before actually growing users, and for a while, it had more developers than users.
In the very beginning, it was a one-man project, but after some time it was picked-up by Mozilla research as an official research project, with several developers working on it (brson and pcwalton in addition to the language creator) and they also started a research new browser (in partnership with Samsung) using this experimental language. That's when people started to hear about Rust (and it was still very far from 1.0 at this point).
Oh. That really surprised me, as I had assumed the bugbears I have as an occasional nim user were because it was developed for/on Windows primarily. Actually bothering to take a look seems to show me that isn't the case at all.
Bugbears such as the linking story on Linux¹, the argument handling², the style and verbosity of the compiler output, [a bunch of others]. Nothing show stopping to be fair, but a bunch of things that just seem out of place(and that always seem to require explanation when co-workers see a nim tool).
1. https://github.com/nim-lang/rfcs/issues/58
2. https://nim-lang.org/docs/parseopt.html , although alleviated by argparse to some extent.
1. Arraymancer https://github.com/mratsim/Arraymancer
2. The new version of the garbage collector understands move semantics to optimize its reference counting so unlike Rust where you have to deal with it yourself Nim will handle it for you at the expense of a reasonable amount of memory. https://youtu.be/yA32Wxl59wo?t=855 Watch the whole video for more context if you care.
I think it's a really nice language, too many pragmas but still really nice.
I really think that the folks behind Nim need to focus on getting some killer apps in the ecosystem and in marketing them. That's all Nim needs. Just some useful tools wrapped in a nice package.
Anyone out there who has used both and has more observations?
For numerical computing however Julia wins hands own purely based on the community and libraries.
I have another use-case; first-class (easier-than-others?) cross-compilation support.
I had to build a one-off tool that was a a glorified "curl wrapper" with validations, for Windows; on a Mac. Wrote a simple nim script, cross-compiled for Windows, and it's been fine and dandy for a year now :)
I'm sure other languages support this (golang?), but Google's SEO suggested nim-lang.org
Carp also has open pull request for using zig as a cross compiler FWIW
Also, I'm with Araq on this one -- in my experience, every time I reached for a cyclic-cross-file-type-declaration, there was a much simpler acyclic solution I found later.
I had forgotten how irritating creating header like declaration files were till I tried Nim.
I expect the developers to know this, since its accessible only though the `$ nim secret` command.
This feature is meant to make linking easier but it shouldn't have leaked into variability of a single module's sources.
Now you can learn a bit about Nim and have fun doing it :)
A couple of links:
https://docs.google.com/document/d/1eYRTd6vzk7OrLpr2zlwnUk7m...
In short, while Go has deliberately shunned all modern developments in PL design, Nim has embraced them. Also Nim has real macros, while Go does not.
It's clear to me that though immature, Nim is a much better and more expressive language than Go.
Therefore, I think the two languages appeal to different sets of people.
[0] https://commandcenter.blogspot.com/2012/06/less-is-exponenti...
Also it's faster than Go on most benchmarks.
This is no small thing. The expressiveness of a language makes the difference between happy productivity and tedious typing and swearing.
Nim is in the same ballpark as Python here, while many other languages require a lot of boilerplate.
After adding a million requested features it will end up bloated like all the others . . .
[EDIT] recognized your nick from IRC a while back, my "good idea" is still to add support for 80-bit floats ;)
Using "no memory leaks" and "reference counting" in the same sentence is #fakenews. Reference counting leaks cycles unless accompanied with a tracing GC (at which point reference counting makes little sense).
Python proves otherwise. Reference counting gives you deterministic memory use and finalization except when a cycle is involved. The tracing GC helps for those cases (and libraries) that do introduce cycles.
If each one of your objects is in a cycle, then -- yes, reference counting makes no sense. If only 1% of your objects are in a cycle, it makes 99% sense.
So anyone can dress like Moses, come down off the mountain with tablets, and we'll debate the scriptures without considering the provenance? Good to know. California ballot initiatives often work that way.
I know it's not a big deal but it seems borderline superstitious to me.
(I chose not to learn go because of it's lack of generics and exceptions. It seemed like a huge step backwards)
It's far from perfect but it does work (and has for a few years), and it helps you by requiring proof that actions are disjoint. There is work now on including Z3 which would work this much smarter.
https://nim-lang.org/docs/manual_experimental.html#parallel-...
So only time will tell if BDFL based language comes up like Linux or design by committee like language. Right now Rust is not that significant like Nim and Zig so all have a chance to come up.
Once there are substantial software written in them like C or C++ than only will know, right now among modern language only golang and Swift reached that stages as being significant systems programming language in spite of GC. Indeed I doubt if Rust will be as revolutionary as Lisp or Haskell or Smalltalk in terms of contributions for the development of compilers and language designs.
No, it's not hard at all to implement efficiently as long as objects don't cross a thread boundary (and e.g. Nim's older GC used to enforce that condition, an old version of K tracked it and switched to "lock; xadd" to count references when something did cross a thread boundary IIRC, which made it inefficient only for those objects that crossed the boundary which usually weren't many.
It's way simpler than multithreaded mark&sweep, for example. Regardless - it makes a lot of sense. It might not make a lot of sense to you, but it does in general in most contexts.
Pascal dialects, while much safer than C, suffer from use-after-free and possible memory leaks, also you don't need to mark unsafe code as such.
This includes any modern Pascal variant.
* Backends: Nim compiles to JS both directly, and indirectly (emscripten) with various trade-offs (e.g. 64 bit ints require emscripten). It also compiles to C, C++ and Objective C giving you the simplest most efficient FFI to those languages one can hope for (including e.g. exception handling) while at the same time addressing the largest set of platforms (got a C compiler? you can use Nim). And you also have (almost but not yet quite production quality) native code compiler NLVM. What's the platform range of Kotlin's AOT?
* Metaprogramming: Nim's metaprogramming ability is second only to Lisp[0], I think, and only because Lisp has reader-macros (whereas you can't ignore Nim's syntax with macros, as flexible as it is). For example, Nim's async support (comparable to Python and C#) is a user-level library. So is, for example, pattern matching. Can Kotlin do that?
* Size: Nim compilation through C produces standalone and (relatively) tiny executables; it matters for embedded platforms. How does Kotlin fair in this respect?
[0] Lisp, scheme and other Lisp derived languages, of course.
* Faster compilation.
* Tooling is less memory-hungry.
* C++ interop.
* Macros.
There are some other languages that have metaprogramming abilities equal to Lisp. For eg. Rebol, Red & Forth.
I think some people would also consider Prolog and Smalltalk to be in the same ballpark.
And there are languages that would also claim to be second only to Lisp, for eg. Julia, Elixir, Raku/Perl6 and probably some others to!
It also compiles to C, C++ and Objective C giving you the simplest most efficient FFI to those languages one can hope for (including e.g. exception handling) while at the same time addressing the largest set of platforms (got a C compiler? you can use Nim). Wow, nim has implemented that much transpilers? This is kinda impressive but I would rather want a language that compile to Binary instead of compiling to another language, AND that offer nice FFI interop Kotlin has state of the art language interop through graalvm but here it does not qualify as native. For native interop it can be done but is subpar. But openjdk is working on a new API luckily.
Metaprogramming Interesting topic for sure! I've never learnt a LISP. I did use macros when I was doing C/C++ and honestly I don't get their advantages vs @Decorators() (pre compile time codegen) and they have a reputation of breaking IDEs Kotlin like Java can generate code/classes at runtime and has full support for reflection. Tangeant: Kotlin can mark any function as in/postfix which allows to easily create DSLs. Due to this Kotlin community has created a lot of elegant, declarative DSLs such as for testing.
Nim's async support (comparable to Python and C#) is a user-level library. Kotlinx.coroutines is the official library the language simply has to expose the keyword suspend.
So is, for example, pattern matching. Can Kotlin do that? Kotlin has some pattern matching features in its when keyword,but no it cannot currently destructure in when. But the subject is active and it should come in a following release, especially since Java is getting pattern matching. https://github.com/Kotlin/KEEP/pull/213
But if your point was that macros allows to modify the abstract syntax tree, Kotlin compiler plugin API offer much more power (you can modify anything anytime (the AST, the IR, the bytecode) It is arguably far harder to use than powerful macro but it does not prevent experimented guys from scalaifying Kotlin through https://github.com/arrow-kt/arrow-meta/issues They are bringing for example union types as an unofficial extension to the language. They could bring pattern matching earlier in theory.
Size: Nim compilation through C produces standalone and (relatively) tiny executables; it matters for embedded platforms. How does Kotlin fair in this respect?* I'm afraid kotlin is not made for such a use case but today even embedded platforms should have a few dozens of free MBs
As for multi platform io they are working on it https://github.com/Kotlin/kotlinx-io