# A critique of Nim ## Forewords
This is an attempt to provide a constructive critique about the language from the experience of a new user. As such, Nim veterans should try to read it with some empathy and Nim novices should not take any statement as a source of truth. The core team should not think this is a personal critique to them, I have the utmost respect for the job you've done and I write this hoping that it can be of help. Moreover English is not my mother tongue, I've done my best to proof read it but I apologize in advance for any spelling or phrases that might be hard to understand. Please ask for clarifications if something is not clear before jumping to conclusions. ## Language ### First impression Nim has a distinct feeling to it from many other _upcoming languages_ , it promises efficiency via static typing while targeting the expressiveness of dynamically typed languages, all this without cornering the user into a safe subset that excels at a given domain but suffers for everything else. That's a great feature on itself, a language that's general enough that can serve you well for years to come no matter what the task at hand is. That generality however goes against the current trend of domain specialization in many languages, but to be honest, unless a language already has a killer app (i.e. Ruby on Rails) I think it's best to opt for that generality. I think this should be more emphasized on the website. As its distinctive traits there is of course the _significant whitespace syntax_ that will attract some people and disgust others, nothing can be done about it since it's a very subjective topic. Then there is the whole _meta-programming_ machinery, that while impressive at the technical level is a double edge sword for a language, some people will immediately discard it while others will love it and probably most of them simply won't know what is it good for. Unlike with the syntax however there are objective reasons to look with suspicion at a language with _meta-programming_ as a core feature, code is read much more than it's written and on many cases _meta-programming_ becomes an addictive joy when writing code, unfortunately others will have to read it later, maybe even yourself when the time passes. That's why I think that any language that offers these capabilities must make them gradual (i.e. generics vs templates vs macros), have awesome reporting/debugging stories for it and most importantly offer always runtime alternatives to the _meta-programing_ so the language is useable and productive without them. ### On boarding experience Once you start with the language, the first 5 minutes feel great, if you're familiar to the _significant whitespace syntax_ it makes you feel at home and with a promise of great performance! But then the illusion breaks, it's a typed language after all so the compiler starts behaving like your worst enemy. That's normal and expected, nothing wrong with the language, the on boarding experience though should be tuned for this crucial moment, preparing the user for that feeling. The compiler should help a bit, try to add an `int` and a `float`, suddenly you're exposed to a zillion overloads of the `+` operator all repeating the same message, you might not even know that you can override operators in Nim at that point! Then you learn a bit more, operator overloading seems so cool! You want to try by yourself and then you stumble on to something called template, which is a _meta-programing_ construct but it's a _simpler version_ of another thing that looks even cooler: `macro`. Suddenly you're exposed to a full new world that is very attractive and very _ergonomic_ to use, so your instinct is to go down that path. Unfortunately while some higher level constructs like generics are well defined and understood at large by many users, full blown AST macros is a different story. It's a very powerful tool with lots of sharp edges and probably only seldom needed. In Nim however you're almost encouraged to use them and I think that's a mistake, there is already a great higher level general purpose _meta-programming_ tool in the form of `template` (without _term rewriting_ ), that should cover most use cases so any reference to real macros in the docs should be prefaced with _there will be dragons_. It 's not Nim's fault that macros are hard, they are just a very blunt tool at a conceptual level and as such any implementation is going to flawed, that's why I think that Nim should place some resistance to its use, a pragma could probably be enough. ### A fews days in Anyhow, the main issue with the language is that from the very beginning you're confronted with a huge cognitive load that is not easy to handle. Look for example at the [Official Tutorial](https://nim-lang.org/docs/tut1.html), the surface of the language is too big and while I'm not in a position to argue about the need or not of all those features, I think that some of that complexity should be initially hidden, offering discoverability paths as the user progresses. Let's see some examples: > * string formatting needs a better story, there is a new `strformat` module > that implements Python's syntax but the user needs to import the module > explicitly, however on `system` there are plenty of functions that will be > seldom used (i.e. GC_xxx). Moreover it can be used as `fmt""` and `&""` which > maybe is convenient in some edge cases but being so simple in Nim to create > an alias with a `template`, experienced users can just do that when it makes > sense. For me `&` means concatenate not _interpolate_ , if anything `$""` > would have been less surprising here but anyway that's syntax bikeshedding > which would take us nowhere. > * Slicing syntax is a bit surprising, the default `..` is inclusive on both > ends ([Dijkstra wouldn't be > happy](https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html)) > and then there is [this > pitfall](https://github.com/nim-lang/Nim/issues/6216#issuecomment-321438673). > The point is that having a different default from other popular languages is > totally fine, you can just learn the new way after a while and then it > becomes natural, however it must be rock solid and predictable otherwise your > mind is always second guessing itself and it never becomes second nature and > frees space in your head for other more important information. > * There are too many symbols in `system`. I think it would help to keep the > impression of a smaller core language if some of them were moved to specific > modules and imported when required. > * Imports are... well they don't help. I have a few ideas from previous > languages with meta-programing features about how to handle imports more > safely, but that ship already sailed I guess. What I think can be done is try > to make all the examples in the documentation use the `from module` syntax > for explicit importing. Users will end up knowing about `import` and > (ab)using it, and it certainly makes writing code simpler if you are all day > working on the same code base. But for reading and reviewing code... explicit > imports are very helpful. > _Greping_ I think deserves a special mention, features like _smart casing_ , _universal call syntax_ and the overloaded operators make the language hard to grep. That's a big issue in my opinion, it breaks many work flows a user may had already interiorized from other languages, in Nim some generic tooling on the command line or built into editors won't always work. I think it's a problem that should be acknowledged and reflected explicitly on the docs with common workarounds on how to configure editors and such. No amount of custom tooling can solve this, people are used to their tools and the language doesn't help here unfortunately, you can't have everything I guess. ## Compiler and tooling The compiler is pretty fast which is a great _feature_. The code is accessible although it 's a complex piece of software. I miss some better modularity in it, tooling seems to be implemented directly in the compiler and then just a façade for the tool. This is fine for a young project with a small user base but to scale some refactoring is needed in my opinion. The language ecosystem could use some more external projects, that helps with visibility, and also allows for competing implementations to iron out issues and establish the best solution. It would be ideal if the parser could be fully decoupled from the rest of the machinery enabling anyone to create tools for the language just by importing a simple module. Diagnostics are mostly fine from what I've seen so far, although I would suggest to have a default mode that is less verbose and more user friendly. The example about the `+` overloads for instance is something that should be improved, if it's going to print all the overloads the diagnostic should collapse them to avoid repeating information, otherwise it's a wall of text that scares the user. I don't have an opinion formed yet about the variety of implementations for GC and codegen. Although I could argue that it does increase the cognitive load of the language somewhat, too many options can be scary. I guess it's a required complexity but I wonder if instrumenting the compiler in a different way would help to move some of those implementations to external repositories. That would allow different maturity levels on them and decouples release cycles, which is more overhead to manage but it'll help to focus the compiler development on a reduced set of fully supported variants and allow the different implementations to mature independently at their own pace (or rot if not enough people is actually interested on it). As a minor note, the CLI interface feels weird to me, I think I've used the `--opt:value` syntax with Mono long ago. I think this just adds a bit to the barrier of using the tool easily for no real gain. I would love a new `nimc` binary that follows posix best practices for the CLI though. Any language needs great tooling and in my opinion the more features a language has the better tooling it requires. For solo projects is fine but when working in a team you need to ensure proper code style and static analysis checks to allow code reviews to focus on the task and not on minor details about white space preferences. I've seen that there is a recent `nimpretty` tool that should work on enforcing a code style, however it's not mature enough for what I've seen. This is the kind of project that could really benefit from being outside of the main compiler repository, allowing more agile development while it matures. For a language like Nim, with all its meta programming powers, I think that there is plenty of room to research new kinds of tooling that allow to keep it under control for larger teams. ## StdLib The initial feeling is that the stdlib is _bateries included_ and that you can probably make do without external libraries for most of your tasks. The problem is the scope of each module. I do like the idea of having a very complete stdlib but it's a huge undertaking to build and maintain one. Perhaps it's best to focus on a smaller stdlib and prime the ecosystem to generate more specialized solutions, bringing then the best in class into the stdlib for future versions. ## Documentation Not pleasant was my initial feeling, although I'm now liking the advantage of having the whole manual in a single file in order to quickly search. But I think it should be split by default. The Official Tutorial is a good guide but it's not working as a _tutorial_ , it should probably be replaced by the Nim Basics one. Overall I think some of the complexity aspects I mentioned when talking about the language can be palliated with changes in the documentation. I would suggest to extract any references to `macro` to a separate document that's labeled as advanced and explains the rough edges of the tool so it serves as a warning to novices to avoid it and look for other solutions if possible. ## Marketing In general I find that there is excessive focus on technical details instead of language features. For example, I don't really care that there are multiple GC implementations to choose from, that's an implementation detail that I'm sure is very useful for some use cases but as a first time experience I want to know what types of software I can create with Nim and how will it help me creating it. Next the focus should be put on tooling, people expect a variety of tooling at their fingerprints from the get go. Packing is taken for granted, it needs to advertise the whole set of linting, formatting, debugging and of course cool editor and IDE plugins. I think that kind of marketing is crucial to attract different user profiles, and having a diverse user base is very important to make sure that the language evolves successfully. It's also a great help to have higher level marketing material when you try to introduce a new language at work, every coworker will have its favorite _toy language_ so you can't sell it saying that Nim has multiple GC implementations, there is probably an obscure language lost with 3 stars on GitHub that has the coolest GC technology known to man, it's impossible to compete in that axis. The language needs to show maturity and that's done with great documentation and excellent tooling mostly. ## Community It's small but active from what I've seen. I'm not much for chats but there seems to be a healthy communication channel there. On GitHub though it doesn't feel very welcoming, some discussions about language design tend to get heated on all communities, specially if there is syntax involved, which allows everyone to try to contribute. However in pull requests I think the project members should make an effort to be more gentle, little things like thanking for the contributions even if they are not finally accepted can go a long way in bringing new contributors to the project. I think it'll be great if some easy low-priority issues had instructions, maybe it takes the project members longer to write them than to actually fix the issue but it's a great way for new contributors to start getting their feet wet. I understand that some things must have been discussed endless times which must be really tiring, and that every new user comes with a bag of brilliant ideas that would make the language great, "because now sucks?" I guess is your inner reaction. But I think new users bring something vital, a new perspective and the necessary feedback loop to know if those features that were carefully designed and took away endless hour to implement are actually working or not. In my opinion it's the ability of bringing new users what makes evolving a language possible, people with different backgrounds and with different requirements that will help shape the language and if done properly will in turn bring more people to it.
