Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Nim 2.0.0 RC2 (nim-lang.org)
229 points by WithinReason on March 31, 2023 | hide | past | favorite | 193 comments


This is very nice since it is progress towards 2.0 and a LOT of bugs were fixed. Kudos to the contributors! The element of novelty in this case are the error messages (which are very precise although not too easy to parse). In the meantime if you are curious how being on HN homepage affects traffic, analytics of nim website are public: https://plausible.io/nim-lang.org?period=30d


I love Nim so much. I really hope some big company decides to use it as their workhorse language - it feels like the only thing holding it back is the lack of corporate 'buy in'. Most similarly good languages (except F# maybe?) seem to get lucky with becoming a poster boy for at least one company.


>Most similarly good languages (except F# maybe?) seem to get lucky with becoming a poster boy for at least one company.

This one I still can't wrap my head around. F# basically was the source of almost all innovation in C# and C# still is missing some features and was not designed in the same way as F# so a lot of the features they "stole" feel tacked on.

Microsoft should have just made F# the C# successor.


> Microsoft should have just made F# the C# successor.

You underestimate the importance of compatibility and familiarity for existing developers. You can show C# code to any C++, Java or even JS programmer and expect them to grasp the idea of what's going on very quickly. This is a big deal and should not be discarded lightly


In terms of looks mostly it just doesn't have as many types and fewer parentheses. Shouldn't be an issue if you know python.


In my experience, Algebraic types alone take some work to get used to using competently. That's just one F# uniqueness and there are others. Learning Elm (a similar language) definitely made me a better engineer, but I really don't think learning F# is the same as learning Python for someone with experience with imperative/OO languages.

I think the reason it sometimes seems like it is that easy is that, as we gain experience with tools, we tend to forget the difficulties we had learning them.


I had difficulties learning OOP, I always preferred a more functional style, despite "consensus" needing 20 years to catch on that functional programming alleviates a lot of the issues we have with OOP.

Learning F# it instantly clicked.

OOP learning issues IMHO are intrinsic to the style, because it's just so seldom helpful in making programming easier.

Design patterns are just a symptom of this issue. That OOP is just a misunderstanding another.

"Real" OOP as practiced in Erlang/Elixir is quite useful.


I think they are making F# the successor but very slowly by evolving C#. I would also have preferred the direct path.


I had a brief look at F#, it didn't fit my mental model and I looked away. Meanwhile I do like using the tacked-on functional features in traditional languages because it allows me to get the benefits when it fits what I'm doing instead of having to fully buy in.


You're just using the tacked on features as syntactic sugar. You haven't "bought in" at all.

I was traditionally trained like you under OOP and procedural methodologies.

After encounter FP I fully bought in and developed two mental models. The fp model lives side by side with the the oop/imperative model.

With equal knowledge in both one can make a more unbiased judgement. The fp model is actually superior imo.

I largely have the opposite strategy now when programming. My mental model is largely fp, and I occasionally cheat and sprinkle in procedural or oop syntax here and there as syntactic sugar.

The basic realization here should be that mutating shared state should be avoided and segregated as much as possible.


> syntactic sugar

To be fair, all languages are syntactic sugar over asm which is s-s over CPU machine code. A mental model is just that: a model for something physical that's in your head. FP or OOP are both mental models for programming in nearly any language. Some languages have first-class FP or OOP features, and some don't, but you can tack-on either of these, and others, to nearly any language you want to. It's really dumb to look down on others choice of mental model if it works for them. I have seen successful projects that were designed around both OOP and FP models.


Garbage collectors, type systems, modules, polymorphic functions are not syntactic sugar. Asm also isn’t syntactic sugar, if only for the polymorphism (how many different CPU instructions are MOV in Asm again?); or just the fact that it’s text and machine code is binary code, while desugaring code doesn’t change its language.


F# is such a nice language. A great modern ML language on the .net runtime with full MS package support that's pretty awesome. But unlike something like Scala on the JVM F# is so simple and straightforward, it has a lot of features without feeling bloated. The fact that MS has just abandoned F# is disappointing.


> Microsoft should have just made F# the C# successor.

their target audience does not want this



he said he works on some internal tool, but not clear how wide is adaptation outside of that.


Yup, corporate buy in is a big deal. Years ago I tried using Nim for a network daemon, but the sheer lack of even the most basic http libraries prevented me from doing it and I went with go.

The library situation is a bit better now. But without a big company contributing in terms of libraries, the language usage will just be very low.


Nowadays atleast Nim has multiple compenent http libraries, see https://nimble.directory/search?query=http


Not in that list, but nim-chronos also provides a solid http server/client:

https://github.com/status-im/nim-chronos


Ditto! Nim is just easy and incredibly fast (to develop and the code!). Our code base is Nim based - even normal bash script have been replaced!


What app are you developing with it?


A full project management platform for construction projects. Webserver, websocket, microservices, etc.: https://cxplanner.com


While we’re not a big company, my work uses it as our secret weapon for embedded firmware development.


If only it supported RV32IMAC and/or XTensa one could use it on one of the ESP32 variants.


Nim supports both since it compiles with pretty much any C89 C compiler. Also https://github.com/elcritch/nesper :)


Oh nice! This looks very tempting…


Feel free to drop by Discord #embedded if you're tempted enough.. ;) I've had production devices running on it for years.


We use the ESP32-S3 as our main microcontroller!


Do you do FPGA designs with it, or just bare metal software?


Software on microcontrollers :)


Programming language adoption -- like the adoption of many technological products -- is usually really fast. With the possible sole exception of Python, all programming languages, popular and unpopular alike, have reached the general ballpark (i.e. high/mid/low) of their all-time peak market share within 5-10 years. Dark horses are very, very rare.


C++ was designed in the late '70s-early 80's and reached peak popularity in the mid-to-late '90s. JavaScript appeared in the mid-'90s and didn't see broad adoption until about the '10s. I would say that the norm is for peak adoption to happen at around the 10-15 year mark of original release. Languages that get adopted faster than 7 years are unusual, and it indicates that they came out at highly opportune times to address specific needs. I'm thinking in particular of Java and Rust, for example, which both reached critical masses of adoption very quickly.


C++ was released in 1985 and it neared its peak market share by much closer than a ballpark in its first decade. JS did the same.

> Languages that get adopted faster than 7 years are unusual, and it indicates that they came out at highly opportune times to address specific needs.

Not only is it not unusual, over hundreds of languages I think there has really been one exception (for 10 years; maybe not 7). At age 10 how well a language does is more or less how well it's ever going to do. I am not saying this is a prediction, but it has been the case historically with almost no exceptions. Any language has the chance to buck this trend, but it has been the trend.


JS took well over 10 years to reach massive popularity. C++ took a bit over 10.


That's a definite no on either one. JS was very popular (top 5-10) in 2006 and C++ was very close to its peak popularity in 1995 (and already declining five years later). Maybe Ruby took 11 years, but that's close enough. Over scores or even hundreds of languages, I think Python is the only clear exception. It wasn't unpopular in 2005 (it was in the top 20), but it certainly moved up a rank from middling popularity to super-popularity well after 10 years old.


I can't see how there should be a reliable pattern in language usage like that. Javascript is more used that ever - who knows were the all-time market share peak is - but we're well beyond your 5-10 year time frame. Could you name any languages that actually have this pattern? Julia maybe.


All languages, except possibly Python, have followed this patterns. Read my comment carefully: I said that virtually all languages reach their ballpark market share within 10 years. JS did reach its high market share ballpark within a decade.


Essentially nobody was a "JavaScript Developer" in 2005, 10 years after JS's release. JQuery didn't exist yet, the term "AJAX" hadn't been coined, and NodeJS was years away. Web developers were using JS to enhance pages, but it wasn't a language that was widely used to write applications. I don't know what the popularity numbers looked like so I'm not saying you're wrong, but it was definitely closer to 15 years before people started to take JS seriously.

JS aside, I think there's probably some survivorship bias going on here. I don't think there are a lot of 15 year old, relatively unpopular languages that are still under active development. Maybe it's not that languages that don't become popular in 10 years never will, but rather that languages that don't become popular in 10 years tend to be abandoned by their developers, thus sealing their fate.


JS was a very popular language in 2006 (at least in the top 10 if not top 5) -- a lot of people were doing at least some JS development -- even though it grew bigger later. Nevertheless, JS (like Objective-C and Swift) is indeed special in the sense that it's the "monopoly language" for a particular platform.

> I don't think there are a lot of 15 year old, relatively unpopular languages that are still under active development.

There are quite a few. If you look in virtually any language ranking, places 10-40 have many 10 year-old and even 15 year-old language. Here are some continuously developed >=15yo languages that are less-than-middling-popular and have always been so: Common Lisp, Racket, Clojure, OCaml, SML/NJ, F#, TCL, Haskell, Idris, Groovy, Squeak, Erlang, D, Ada, Nim. There are more of these than there are super-popular languages. (I didn't include any language that was, at one time, at least somewhat popular but is no longer, such as Visual Basic, Delphi, and Perl 5).

There might still be survivorship bias, but I am not saying all that is fate, just a clear historical observation.


I understand what you are writing. But it only holds for you because your idea of ballpark is exceedingly wide. It's doesn't hold at all for the usage numbers I look at without your socalled ballpark being several magnitudes.


JS's market share did not grow by even one order of magnitude since ~2006 nor even close to an order of magnitude. There aren't that many orders of magnitude for a share to grow if you start counting at ~1%.


In general you are correct. However, language adoption can skyrocket when some new library/framework arrives which has a compelling reason to switch (e.g. Rails for Ruby)


ocaml managed, but it took a significant effort to improve the general tooling ecosystem


Unfortunately, it's too good of a language for serious corporate adoption...


Companies base their choice of tools on how easy is to find developers to hire, therefore Nim and other similarly young but very powerful/optimized languages (Crystal, Zig, ...) need many independent developers, who can base their choice purely on technical merits and personal taste, to use it and put it into their resumes before the corporate world can notice and add them into their list of accepted tools. It's a quite slow process though.


The main problem is people afraid about Style Insensitivity it enables by default .


Its set to produce a compiler "Warning" by default now.


(for inconsistent usage)

As background, style insensitivity was introduced so that codebases can use a consistent camelCase or snake_case regardless of the style used by upstream libraries.


Which as an aside, makes writing and using C bindings so lovely.


Well, maybe not writing. Occasionally low-level C libraries - especially those that deal with keyboard input - decide to provide identifiers differing only in case... There's a WIP RFC for providing a way to deal with identifiers that need to be verbatium by surrounding them with backticks, though.

https://github.com/nim-lang/RFCs/issues/477


I am in a position to do this and I picked kotlin instead as the tooling is not good enough yet. Without a good IDE experience you lose some of the productivity that nim potentially offers.


As a reminder, at Nim Conf back in October 2022 Andreas presented Nim 2.0 in this video https://www.youtube.com/watch?v=aDi50K_Id_k&list=PLxLdEZg8DR...

Hearing again I cannot chuckle when Araq says: Nim v1 is good at everything, Nim v2 is supposed to be better at everything.

Back then it was supposed to come out in 2022 and indeed a RC1 came out in Dec. In the blogpost for RC1 you find the desciption of all new features: https://nim-lang.org/blog/2022/12/21/version-20-rc.html

This longer time is because extra care is being taken into having a smooth transitions (for example important libraries have been tested to work on nim v2, e.g. we made sure nimib was working with v2 in early Feb: https://github.com/pietroppeter/nimib/releases/tag/v0.3.6)


The smooth transition can't be overstated. Its such a breath of fresh air, when many platforms, libraries just drop support all the time.


Some background: I spent years in C++, then many years in Java, Ocaml, Python, Rust and even APL - everything is for production. My last pet-project was on Rust also, and it took about 2+ years and I felt pretty depressed about IT at all.

One of the part of the project (feed collector) I tried to write in many languages to compare. One day I downloaded Nim - did not expect anything at all - just wanted to try async and ... in about 2 hours (on new language for me) I had the same functionality I spent 2 weeks in Rust. More interesting - it was about 30% faster than Rust solution.

After it, I can just show the picture: https://user-images.githubusercontent.com/4949069/229308266-...

I rewrote full (2 years+) project in Nim in 3 weeks. I understand that I knew good architecture for the second implementation, but 3 weeks is good anyway.

Did a lot of pet-projects, I use it for small prod tools or research if it is possible.

For example I wanted to extend atop functionality, and I wrote my own ttop: https://github.com/inv2004/ttop

For new Nim's user I would describe it like python with speed of C-lang. But later you will find that it is not another python, it is its own language with a lot of powerful things like templates, macros, very good interop with C (that is why libraries are not a problem most of the time) and etc.


Also, I would like to mentioned that I was impresses how much the Nim is perfect shape with quite small team of core contributors compared to many other languages. There are some bugs, of course. nimsuggest (main thing for LSP) is not in the perfect shape. But I did not have any feelings of unfinished product like Pony-lang, Crystal and etc


Nim rocks and the ecosystem has made some great strides lately. I highly recommend checking it out

One awesome project is https://github.com/jmgomez/NimForUE


I noticed Nim allows using the Go GC as an option. How does this work? Does it compile into Go as a target language? Or can it link with Go's (ever changing) ABI? Or is the Go GC available as a standalone C lib? I'm just curious how this works...anybody know?

EDIT: I think I found it - looks like it actually isn't new: https://forum.nim-lang.org/t/1278. Sounds like the answer is: Links via GCCGO to their channel implementation. Compatible GC was written in Nim to go with it.


OK, so we have languages for nearly every niche now; Zig has it's allocator thing and goes with C very well, Go has goroutines and channels and CSP, Python has data science, Java has support/libraries for everything, etc.

Let me suggest a new one: a language which is top-dog in it's language interoperability. Imagine a language that can do nearly nothing except glue together code from other languages. Maybe you want to call some Java code from some Go code from some Nim code from some Python code from your C program: this language would do that for you somehow.


That’s just python, and I’m only half joking.

Another idea for that would be GraalVM’s Truffle. It’s not a language, more of a universal VM, but it can actually already just eval some python code, use the resulting code from Java and pass it on to JS. It also has support for any LLVM language, so C can be invoked from/be invoked from any of the aforementioned languages. And it can even optimize across language boundaries, pretty incredible.


Nim has an edge over Python as it can compile to C, ObjC, C++, JS. Meaning it can do native FFI in each of those. It can also compile to really fast and small WASM too.

However it takes a long time to accrue enough good wrappers and bindings.


Remember when Python was described as a glue language that was also good for prototyping?

I guess business just ignored the prototyping part.


ha - I've had my "interop" language in my head forever. FFI primarily by generating code directly into every lang (haxe-style), but ideally with a better lang behind it (imagine Python and Rust had a baby). Oh if I had the time...would be fun.


For a year or two now, nim has been what I've enjoyed programming in the most. Thanks to everyone involved. The new improvements are much welcome.


Can't get past the style insensitivity thing. Seems like a ridiculous 'feature' to build into a lang.


The only situation I can imagine this causing a problem in your codebase is if you intentionally want to mix camelCase and snake_case in your codebase and these 2 meaning different things. So if you don't enforce in your codebase a specific code style practice and you would like someFunction and some_function to coexist and mean different things, then yes. Nim's approach is problematic for you.

If you enforce a code style or, if you don't but you would convene that someFunction and some_function should mean the same thing in your codebase. Then nim's approach should be transparent to you.


It also makes it harder to grep. If you're on a team of 10 devs someone could have accidentally forgotten an underscore sometime last year. So you can't just grep for 'ready_for_upload', you have to use 'ready_?for_?upload'


This is a valid observation.

I suspect, in practice, almost everyone follows the sane approach of enforcing a code style in your codebase. I think what usually gets lost when this is brought up is that the point of this code style insensitivity is not to encourage you go to crazy and mix and match it in your projects. It's so external dependencies don't have to infect your codebase. So you can actually apply a consistent code style within your project.


There are warnings raised by default, like this:

test.nim(2, 8) Hint: 'myvar' should be: 'myVar' [var declared in test.nim(1, 7)] [Name]


I think there was a flag that allows you to turn bad style in identifiers into compile errors. It isn't but imho should be on by default.

edit --styleCheck:error perhaps?


Tooling (In this case, "Find References") should understand language semantics. Not that I think that this specific feature of Nim is particularly appealing, but pandering to 1970s stone-age tooling forever is just sad.


You don't always get to pick your tools. If you're using GitHub, ctrl+F should find what you're looking for.


Again, not if you enforce a code style which nearly always should in a professional context.

Such a mistakes is easy for a linter to pick up on so that the code would never be merged in the first place.


How does the linter treat 'get_file_system' and 'get_filesystem'? Which one would be flagged as an error?


The one that doesn't match the declaration.


An earlier comment says:

> It's so external dependencies don't have to infect your codebase. So you can actually apply a consistent code style within your project.

Say an external dependency has a declaration called 'getFileSystem', and in my Nim codebase I refer to it as 'get_file_system', but last year someone accidentally committed 'get_filesystem'. In this case neither usage matches the declaration. Does the linter flag both spellings because they don't match 'getFileSystem'?

EDIT: And what about reflection? If someone wrote `newCall("get_filesystem")`, will the linter fix that too?


As a C programmer where the codebases I work on have never adopted any sort of style enforcement: sounds like a normal day to me.


Use nimgrep?


Ripgrep is already integrated into my editor and muscle memory. Nimgrep is just yet another special case tool that only exists because Nim decided to spend its weirdness budget on inconsequential nonsense.


The “weirdness budget” concept is nonsense. Are you saying that programming languages should do only some things right?


@Nullabillity The only nonsense we are dealing with constantly is opinions of people who haven't ever bothered to use this feature before declaring it "inconsequential nonsense".


[flagged]


Very mature, congratulations! Naming has nothing to do with style insensitivity. You can write M_ya_wse_s_omEv_ar in any language, yes? Proof that you don't understand what you're arguing about.


> You can write M_ya_wse_s_omEv_ar in any language, yes?

Yes? That doesn't mean that we should add features that encourage that kind of confusion. Especially not when they, again, help nobody and bring no actual benefit.


(Not who you responed to)

Just to argue against there being no benefit, I have a cognitive impairment that occasionally puts me in an altered state, a delirium to varying degrees. camelCase is much more difficult to read at that point, so I can get confused ridiculously easily. I tend leave a bunch of comments and then step away, but sometimes I can work well through it; things like horrendous variable names/regexs will throw me. I default to snake_case but compile over when I share the code.

This is my unique situation and predilection to being able to read one form more easily than another, but it does indeed help me.


That's understandable, but doesn't that cause the same issues when reading documentation or third-party code?


I can back away from those while leaving the tabs open and be not too confused coming back, not having temporarily broken them. When I'm in the middle of refactoring especially though, getting a seizure and trying to back away without jumbling the house of cards is a lot easier with whatever pattern recognition I have around snake_case.

Edit: curious, have a preference besides consistency for cases?


If anything, it encourages a consistent style, since you don't have to use whatever style your dependency uses.

Also, if you work with people that name things like that, it's not really Nim's fault?


Somehow pretty much every other ecosystem can just pick one style and stick to it, negating the problem entirely.

I have never come across a Rust project that didn't use snake_case, or a Java project that didn't use camelCase.


Do you use it regularly? I don't, and I don't have any problem finding what I need with regular ctrl+F in Nim, because Nim projects are internally consistent in terms of style, with the compiler helping enforcing it with `-styleCheck`.

So don't bring up nimgrep like it's a necessity when it's more of a last resort tool nowadays. You will be just attracting flaming.


Can you integrate that into an IDE? In many IDEs, if you hit ctrl-shift-f, it will search the project for the selected text with just one keystroke. Can vscode be made to Do The Right Thing for Nim without extra fiddling on every search?


Your Nim project will be in a consistent casing, otherwise the compiler will be warning you about inconsistent spelling. Regular Ctrl-shift-f will work just fine.


Good question, but I don't know the answer (yet) because I don't use vscode, sorry.


Why would someone change its tooling because of a particular Language ?


It would be one thing (but still a weird feature that calls the rest of their decision making into question) if it normalized fooBar into foo_bar (or the opposite). But that's not what it actually does, it normalizes both into foobar, which introduces new ambiguities. In fact, you can often end up with the opposite meaning! For example, a few Swedish examples:

- hand tvättas (wash your hands) != handtvättas (wash by hand)

- sjuk gymnast (sick gymnast) != sjukgymnast (physical therapist)

- sjuk sköterska (sick nurse) != sjuksköterska (hospital nurse)

- lång hårig (tall and hairy) != långhårig (long-haired)

- sjö nära tomt (lake near a house) != sjönära tomt (house near a lake)


Natural language compound words has no bearing on a discussion on Nim. It makes even less sense to use a language full of compound words like Swedish, when Nim is written in English - a language where compound words are less common and flexible.


Nim forces you to use English identifiers?


Nim itself, or the code bases written in Nim?


These examples apply to a codebase...how?


Variables are usually named after things, so of course they apply to a codebase. How would they not apply?


Method\variables naming?


I'm a Swede working in Sweden and Norway, and I've never seen any code written in a Scandinavian language (thank god).


Another situation is when you have to interface with some other language that doesn't have this feature and where nameLikeThis and name_like_this both exist and mean different things. Thus requiring you to work it around with a third naming convention.

Here's one illustration: https://github.com/nim-lang/RFCs/issues/456#issuecomment-111...

We have partial case-insensitivity in PHP. Can't say I'm very fond of it, but I'm ambivalent as long as it's not abused.


You should rename foreign identifiers anyway. C names are usually very cryptic.


This has a drawback that when reading the original documentation, not only do you have to mentally translate the code examples into your target language, but also translate the identifiers too.

And "C names are usually very cryptic" is plain false, unless you talk about APIs coming from the ages and compilers where all identifiers had to be 8 characters or fewer in length.


> The only situation I can imagine this causing a problem in your codebase is if you intentionally want to mix camelCase and snake_case in your codebase and these 2 meaning different things.

This is literally idiomatic Python style! Classes are TitleCase and everything else is snake_case.

I have also used a mix of camelCase and snake_case for different purposes, eg in Haskell where conventions are mixed (and I am far from an expert), I've written names like "fooBar_prev"


> This is literally idiomatic Python style! Classes are TitleCase and everything else is snake_case.

And Nim does distinguish between those.

> I've written names like "fooBar_prev"

That's disgusting.


I'm not sure I understand the rationale of it if using a consistent naming approach (best practice) renders it transparent, and compiler warnings alert you to instances where one is using e.g. my_var and myVar. Seems like the capability is there but the typical advice and compiler both warn against taking advantage of it. Just seems like a footgun to me. What am I missing?


It's there to allow you to have a consistent naming approach inside your project, regardless of the naming approach of the libraries you are using.


This is done a lot in Python Libraries the module with lower_case and class name with TitleCase . In Nim's Case (No Pun Intended) it is a fatal mistake.


This particular example isn't actually an issue in Nim. The first letter of a nim identifier is case sensitive, so while `my_thing` and `myThing` are normalized to the same name, `my_thing` and `MyThing` are different.


It's a big plus for library and FFI interop so external styles don't take over your entire project.

Also, John Carmack: https://mobile.twitter.com/id_aa_carmack/status/159256093820...


Carmack's tweet seems like more of a thought provoking question than an indictment of case sensitivity. I'm not sure I am convinced that a child stumbling over case sensitivity is a smoking gun. I just explained it to my nontechnical partner and before I had finished and proposed a "what do you think?" kind of question, she had given a "oh,hmm" to the idea that "abc" and "ABC" might mean the same thing when used as variables. Again, no smoking gun here either.


Plenty of programming languages have "did you mean xxx?" in error messages. Plus using IDEs means you will mostly autocomplete identifiers anyway. I don't buy it.


The point is to use third party libraries while keeping your prefered case in your code. You prefer your code in CamelCase, but some other guy made a library in snake_case. Still you can use the library using CamelCase, and not mixing.

E.g. The Python Selenium library used to be in CamelCase, while almost all code in Python is snake_case. By using Selenium you ended up with code like:

    my_button = browser.getElementById("Button")
They rewrote the whole library to be in snake_case, a change that forced a lot of code rewrite downstream. Even the Python builtin library has case inconsistencies (logging module is camelCase, sys has both alllowercase and snake_case) that weren't fixed even in 2to3.

Nim would have handle this efortlessly, allowing you to use get_element_by_id or getElementById in the old library, and avoiding you the effort to rewrite your code if the Selenium mantainers decided for a case change. You can refactor your case without fear of making life worse for your users.


An alternative design would be: when you bring in an external library, there's a mechanism to rename the symbols in it.

The downside is that for each library you want to do this to, _once_ you have to spend a few minutes writing the renamings.

The upside is that if you now want to find everything that uses the external function getElementById, you can search for _that_, and you will find the "rename getElementById as get_element_by_id"[1] declaration, and then you know to search your project for get_element_by_id to find all the places where it's used.

[1] I am not suggesting that particular syntax; I just picked something at random.

The other upside is that if you want to find uses of the getFoobar function that's defined in your project, you just have to search for getFoobar rather than doing a case-insensitive regex search for "_*g_*e_*t_*f_*o_*o_*b_*a_*r_*". (Or, if your answer to that is to use language-specific tooling, that you aren't forced to use language-specific tooling when it might be more convenient to do searches on the GitHub website, or in the text editor / IDE that everyone else on your team uses, or in the text editor / IDE that you'd been using for years before starting to use Nim.)

To me, this seems like an obviously better design. I don't want people who have spent years becoming productive in Emacs, or Vim, or Visual Studio, or whatever, to have to choose between using some different set of tools they aren't used to and having the searching operations they're used to using silently do the wrong thing.

Am I missing something? Because, rightly or wrongly, this one weird design decision is enough to keep Nim off my list of languages that are worth the time to investigate: not because this single thing makes that much difference on its own (though it does feel as if it would make my life substantially worse, if I were writing a lot of code in Nim) but because I feel like the language is designed by someone who makes weirdly terrible design decisions sometimes, and if that's what I want then I already have C++ and Javascript :-).


First, you are aware of `--styleCheck:usages` and `--styleCheck:off|hint|error` that by default already warns the user if he is not consistent on the spellings of identifiers? So you ever just have to search by one form inside your projects.

As far as renaming external libraries goes, if the original name is get_foobar, and the project uses snakeCase, I would be very surprised if it's renamed to anything other than getFoobar. There are slightly more tricky stuff like get_ID, but even then there are only a couple of reasonable forms to search for. And it's rare to be searching for things you haven't seen used, and if you saw it used you know how it's spelled in that library.

I've been programming for years in Nim and never had any problem grepping or searching for things because the style insensitivity.

I don't think it's reasonable to force every developer to spend a few minutes writing renamings if virtually all of them are obvious mechanical transformations, just because a paranoia not substantiated by experience.



> you just have to search for getFoobar rather than doing a case-insensitive regex search for "_g_e_t_f_o_o_b_a_r_"

Are you seriously expecting that someone will put an underscore in the middle of a word?


I'm not expecting anyone to turn getfoobar into getf_oobar, no. But (1) there are cases where people might disagree about whether something is one word or two (do you want to bet no one has written "white_space" where you wrote "whitespace"?) and (2) there are weird cases where the same string of letters can be split into words (or sufficiently word-like pieces) in multiple ways.

I don't have a plausible example of #2 in mind. Maybe there aren't any. (There are definitely lots of things that break into words in multiple ways, of course, but maybe there aren't any that make plausible identifier names more than one way. Though for what it's worth I bet there are.) And in any given case you can check, given a few seconds' thought, that there aren't other possibilities. But that little extra cognitive load is a bigger deal than it sounds like -- it's a distraction from other things -- and if you don't do the check then you'll never know whether your search operation actually found everything it should have.

So you can check by eye every time. Or you can write the ugly regexp every time. Or you can just accept that what ought to be a perfectly simple operation isn't quite right and might invisibly go wrong some time.

That's not a set of options I like.


> The point is to use third party libraries while keeping your prefered case in your code.

Third party Nim libraries? Because if the all used the same style this would never be needed in the first place.

Rust never has this issue because everyone uses the same style.


Bleh I don't like snake_case, it results in long identifiers


I agree. It's one of my biggest gripes with the language. It has big effects on greppability. And by extension, it also has effects on search-engines. Both large ones like Google, and small ones like Github's or StackExchange's built-in engines. Even browser-search on an API document could be problematic.

If I'm looking for some example code that uses my_testfunction(), I can't just search for "my_testfunction nim". Instead I have to add MyTestFunction, my_test_function, MYTESTFUNCTION, etc. The case-insensitivity isn't really a big deal, but the underscore-insensitivity is.

If I'm honest, I think this is a big problem for adoption of the language. It's incompatible with a lot of search-engines, and weird to anybody coming from any other programming language. Nim should take advantage of the 2.0 release to do a compatibility break in this area, maybe with a compiler flag to enable the legacy behavior.


Your argument applies to style sensitivity as well to be fair - do you search for 'MyTestFunction' or 'my_TestFunction'... or was it 'My_TestFunction', maybe 'm_Y_tEsT_fUnCtION'?

Style insensitivity lets you automate your local code (and/or through CI) to consistency for easy searching, even when external libraries YOLO their own style.

> It's incompatible with a lot of search-engines

Google and search engines are case insensitive, and mostly ignore underscores too. Let's be honest, how often would you just search for 'testfunction libraryname' on the web and get the signature you need?

My experience from using the language in production for years is that case insensitive searches will find what I want in Nim code specifically because no one can use case/underscores to make things make unique. Instead, the language uses overloading through the type system to distinguish things. This is a far more succinct, safe, and expressive way of writing code from my perspective.

It's worth noting that the first letter of an identifier is case sensitive, with the convention for types to start with a capital letter. So, you can write 'type Test = object' and 'proc test(t: Test)', then use them with 'var test: Test; test(test)' without any ambiguity, and with code completion/jump to source in VSCode (and others).

If you then add 'proc test()' with no arguments, it's still unambiguous because the functions have different signatures, so you can then write 'test()' and your second function is called.

If something is ambiguous, it's a compile time error. If you want, you can prefix modules like Python, but there's never any need. If you have two libraries with the API, same types, and function signatures (such as using two async libraries in the same program), you can just slap a generic '[T]' so it's lazily instantiated at the call site and move on.

IMHO relying on casing/underscore to distinguish identifiers is objectively worse than using the type system to statically and unambiguously prove your intent, and normalising names removes a class of identifier confusion bugs to boot. Even style guides in case sensitive languages beg us not to use case and underscores to disambiguate symbols for the confusing code it creates, and to be honest, I've yet to see a compelling argument in favour of case sensitivity beyond simply being what people are used to.


> If I'm honest, I think this is a big problem for adoption of the language.

Can confirm, it single-handedly kept me away from the language.


Pretty much all Nim projects use a consistent naming style, so this is not a problem in practice.

> Nim should take advantage of the 2.0 release to do a compatibility break in this area, maybe with a compiler flag to enable the legacy behavior.

No thanks, I don't want inconsistent naming conventions in my code.


Most of my complaints about this went away with --styleCheck:error. You might already know about this flag, but some people do not. Most projects I have found stick pretty closely to NEP1.


I cant think of a single situation in which I would want take_action() and Take_Action() to do different things inside of a program. What reasonable purpose would naming things that way serve?

I see it as a mandated style checker built into the language.


Nobody wants codebases with different take_action() and Take_Action() functions. That's a straw man.

The issues are:

1. Difficult to search code. Even just case insensitivity makes this worse because often you do have names that only differ in case (but in an acceptable way, e.g. they're different kinds of thing, or namespaces). But ignoring underscores makes it much much harder - now every search needs to be a regex.

You can say "use an IDE!" and you absolutely should but you still sometimes need to search with dumb grep style tools.

2. Case insensitive rules are always more complex and difficult to remember. Where do they apply? All identifiers or just variables? What about keywords. Nim's rule is especially complex. It adds cognitive load.

3. Extra bike shedding. I imagine they added it to avoid bike shedding? But it will have the opposite effect. They should have just made a language wide convention like Rust. Nobody debates case style in Rust or indentation style in Go because the tooling and community pretty much force one style.

I fully anticipate a Nim linter that bans style variation from the canonical one. If that doesn't exist already.


It doesn't seen like a strawman when in Python you are forced to write like this:

    import logging
    import sys

    sys.breakpointhook()
    sys.exc_info()
    logging.getLogger(__name__)
And both `sys` and `logging` are not obscure builtins, they are used everywhere. And just for that, case is not fixable.


Is there also a `get_logger()` or `excInfo()`? I don't think so.


Why does that matter?


Because the original comment was about two similarly named but different functions. Otherme123's example didn't have that.


1 - Every search? What nightmarish code base are you imagining? That paranoia is not based on experience.

2 - Negligible cognitive load in my experience. You can just ignore that part of the language and treat it as case sensitive and everything will work. Inside projects it's effectively case sensitive too. And the rules just make sense, they are just there to allow you to be consistent in your casing, nothing less nothing more. It applies everywhere they are need for that, and nowhere else.

3. Gofmt wasn't a thing when Nim(rod) started and now is too late to force all projects to a single style. But projects are internally consistent, and you can always use your preferred style, so I consider Nim's a superior solution.

> I fully anticipate a Nim linter that bans style variation from the canonical one. If that doesn't exist already.

The compiler already warns you by default if you are not consistent on the spelling of identifiers inside your code, and you can make that an error too. See `--styleCheck:usages` and `--styleCheck:off|hint|error`. There is a nim linter that can make your code conform to NEP-1, but last time I saw it was a bit too buggy in that style transformation, so people don't usually use it.

I've been programming for years in Nim and never had any problem grepping or searching for things because the style insensitivity. In pratice it's a non-problem.


> They should have just made a language wide convention like Rust.

I don't know about Rust, but Python has a language-wide convention – and programs still violate it, including the standard library.


In JavaScript (the wild west of programing languages) when I see a library that exports names in non-idiomatic ways, or otherwise has a non-idiomatic API, I usually search for a different library.


The DOM API, which is objectively the most important JavaScript library, has an inconsistent naming convention. Specifically, it can't decide whether it wants to treat acronyms/initialisms as words. See for example getElementById versus innerHTML.


I do like Array.prototype.includes vs. Element.classList.contains also which APIs use promises vs. callbacks vs. events. Like I said, JavaScript is the grandmaster of mixing and mashing idioms.


Very rarely though in my experience.


IMHO from a theory POV, it violates the/my principle of least surprise. Compilers are typically strict and I'm ok with that - my mental models of programing are built around that unforgivingness and I like it, because if I play by the rules, I know there'll be no surprises (ideally). When the rules are relaxed, I have to remember more stuff. It's easier for me to know that ABC is ABC, and never abc or a_b_c.

I think I remember reading early remarks from the Nim team that you can opt-in to the symbol sensitivity but it's a marker comment per-file, or some kind of DIY preprocessor which does the same. I'd be happy if it was a CLI switch.

All that said, and in practice, clearly a lot of people are fine with this and even like it. I'd much rather Nim exist with this (IMO) oddity than not at all.


I have extensively used Nim for the past 6 years, and it has never been an issue. I have seen codebases where someone wrongly capitalized a variable identifier, which results in a compiler warning being raised. So no harm done.


Style insensitivity does not really come up once you start using the language.


I was annoyed by it at first, but got past that, and now don’t think too much about it. With tooling support (mainly lang server and nimgrep) I haven’t found it to get in the way, and have come to appreciate the flexibility it provides.


I think the opposite. Case sensitivity beyond the first character just makes life difficult.


Same. Was strongly considering getting into Nim, but screw that, not interested in needing special tooling for something as basic as reliably grepping Nim code, there's too many other languages out there.


In this thread there are people who say "a convention is enough", but then don't give enough credit to the Nim convention. Maybe you are imagining a Nim library abusing this ability, and the same developer writing all different versions allowed: write_file, writefile, writeFile, w_ri_tefil_e...

Nim developers are as smart as any other, and they like and write clean codebases adhering to the convention in NEP1. The ability to mix cases is used to fix libraries without having to disrupt their users.

I've seen this kind of complains over and over: a new language emerges (e.g. Python 20-30 years ago), and what people finds the absolute showstopper is the indents instead or braces, a minimal part of the language that should not bother a competent programmer at all. The same people that were writting old PHP or old Perl, go figure, complainig that Python whitespace is ugly.


It's good to see that they chose the keyword discard instead of the underscore symbol. It's verbose, but at least you can see the damn thing.


The empty `discard` statement is a do nothing statement; it's not part of the type signature, if that's what you meant.


Ignoring a return value is a normal thing in many situations. I like verbose but "discard" is weird enough that it might complexify API design to offer two functions instead of a single one.


You don’t need two functions, you just mark one as {.discardable.} and the discard happens automatically. Unless I’m misunderstanding you.


`discard` isn’t part of the type signature.

The functions in the blog post have void return type because between `)` and `=` there is no `: [type]`.


Even as a "competitor"[1], it's great to see systems languages getting better. I am glad there are alternatives and competition with C/C++, Rust, Zig, etc. Congrats!

[1] Well, not really a competitor, Virgil is never going to hit it big, heh. I'm mostly scratching my own itch and doing research.


The zig author(s) have been in the nim forums a bunch, I like seeing the ideas and techniques bounce around. Your language can output Jars and web assembly modules. How is the FFI? Think it would make sense to use along with nim in the same codebase?

Edit: thanks for all your works btw, it means a lot.


The Wasm target allows you to specify imports (basically "import component Foo { methods... }") and exports, so the resulting .wasm module has those declared imports/exports. There really isn't an FFI for other targets yet, but I get a lot of requests for that, so I am thinking of how to do this now. Probably, the native targets will support import/export and generate a .o that can be linked with C/C++ Rust using the normal linker.


Web framework.

If Nim had a super robust web framework, usage/adoption would skyrocket.

It has all the ergonomic benefits of a language like Python but the perf/memory of C.


Not sure more is needed. I'm building apps with Nim using mummy (threaded server) and Karax (building HTML). Karax can also run in the browser. And that's just the minimal setup, more batteries-included frameworks like Prologue exist. Absolutely no blockers to delivering great web apps in Nim


We really should try to port Django to it. It would be a good fit I think.


Yes!

Since it has first-class support for compiling to JavaScript, it could offer fullstack type safety web development in a single language.

It's also very easy to grok by being Python-like.


That's what Karax provides. Then choose one of the numerous web servers available to serve it. Write additional client-side code in Nim if you want to (nim js -> esbuild). It's all there.


I'm not so convinced. Web frameworks by and large don't need the perf/memory of C, they're always running on high powered servers. Nim feels like it would be perfect for embedded settings.


> Web frameworks by and large don't need the perf/memory of C, they're always running on high powered servers

But if they had perf/memory of C they wouldn't need to run on high powered servers!

If a language allows you to be productive and can deliver high performance that can reduce your ops complexity and your hosting bill, what's not to like?


That implies that we don’t already have high performance web frameworks in managed (thus more productive) languages already, which is not the case. C#, Java, Go are all such languages with plenty of examples.


With that logic, why should anyone use nim at all? Those are the terrible languages we've come to nim to be free of.


I’d love a really good Nim web server option, too. Something lightweight but with enough to quickly build APIs, like FastAPI in Python or maybe Chi in Go.

Even if the speed wouldn’t do it for many people over, say, FastAPI, the static typing and less insane package and dependency management than Python, and lower friction/boilerplate than Go might.


Awesome! Really looking forward to the 2.0 release - specifically default object values, which is one of the few language-level pain points I've had.


Ecosystem-wise - a brief subset of Nim packages:

    https://github.com/ringabout/awesome-nim
packages.json has many more - over 2000.


https://nimble.directory/ for a package directory for the package manager `nimble`


Has anyone reconciled the list of recommended Nim 2.0 changes from last years discussion, to this RC?

https://forum.nim-lang.org/t/9132

https://gist.github.com/j-james/08cd36b7475d461d6291416381ce...


Nim is still on the top of my to-study-to-use list, for c++ backend I'm unsure if it transpiles to c++20?


I have no first hand knowledge, but my guess is their code generator would use the lowest compatible C++ version that has all the features they need - to maximize compatibility. If it was me I would actually be trying to avoid using the newer features of C++ as is shrinks your interoperability.


Why would you want C++20? C++ is generally backwards compatible, so a modern C++ compiler will still compile C++11


c++20 provides quite a list of features on top of c++11 that I use daily these days, would like to know nim keeps up with those new syntax/features as well, seems not yet.


Nim uses C/C++/Obj-C as a sort of abstracted assembly. While it's possible to follow the generated code with some formatting and effort, it's made to be optimally machine-parsable and optimizable. I suggest giving Nim a try and checking out the generated sources to see for yourself.


If those features exist in Nim, you can just use Nim. FFI should probably work on newer libraries too.


I really wish they would fix the static linking. has needed a hack for three years:

https://github.com/nim-lang/Nim/issues/15220



What does some random PR have to do with anything? That is not the Nim repo


Quickly scanning this seems like a Windows-only problem, yes?


I like nim but I found the dev experience to be quite awful. Couldn't just install a plugin for VS code and hit run...had to configure stuff and not sure how to get the debugger to work still.

I have strongly suspected for a while now that the language is kind of irrelevant, but the supporting infrastructure like package managers, IDEs, other utils, platform support, libraries, etc are far more important when picking a language to use. Who cares if java programs are 2x as long? Trying to fix your $obscure_language$ tooling will take 10x as long.


It is a good language. But most good language is just never popular.


We can say “general purpose languages” never gets to be popular There must be a reason of wanting to adopt the language not just because “I like it”


I'm pretty sure there are a lot of projects using some language just because the developer likes it. Even in a company, personal preference could still affect a lot in choosing the language though they might concern more than that.

And after that, the language might become popular because some big companies use it/develop it, or someone makes a killer library. Most reasons are just not relevant to the language itself.


Might give Nim another look. I stopped using it a while ago after getting frustrated with its iterators. Does the v2 improve them? I didn't see anything major about them in the release notes.


What's wrong with Nim's iterators?


I wrote a comment about it a while go:

https://news.ycombinator.com/item?id=34669902

basically Nim has several features which on their own seem great, but don't compose with each other properly. also it's been many months since I used Nim so some of the details may be outdated or misremembered but the overall gist of what i'm saying is >90% true so i don't care if anyone nitpicks this:

Nim has UFCS (uniform function call syntax). so whenever you have f(a, b), you can write a.f(b), and it means literally the same thing (until you read the fine print for the parts where it's not). and you can also omit parentheses when it's unambiguous, so you can write stuff resembling method-chaining or unix pipelines in a totally natural way: foo.bar.baz(x, y).qaaz().quux is the same as quux(qaaz(baz(bar(foo()), x, y))) and way more readable bc less parens and the execution order is left-to-right. it's so, SO, tempting to write lots of code this way, because it's such a rare language feature, and it fits with the way I think.

but it's not just functions, there are a lot of function-like things, i.e. the stuff you can write as f(a, b): methods, ad-hoc overloaded functions, generic functions, templates, macros, iterators, etc. but things don't work consistently across all combinations of function-like objects, argument types, and function-call syntaxes. iterators is one part where the abstraction breaks, and iirc there are a few others (certain kinds of templates?).

there are two kinds of iterators: inline, and closure. inline iterators are meant to be a zero-cost abstraction, basically a for loop that gets inlined at the call site by the compiler, and they're not first-class objects. closure iterators otoh are first-class objects and can be passed around, but they have runtime overhead (idk how much). so lets say you want to make an API that consumes an iterator and does something useful with it, e.g. higher-order functions like python's itertools (Nim advertises itself as being similar to python in important respects like this so it's a valid comparison). great, so then you try to use it on the builtin "lines" iterator (the one that splits a file at newlines and yields each line as a string). oh no, you can't, because "lines" is an inline iterator so you can't pass it to a function.

fine, so the language has handed me this pile of dogshit that I can't do anything useful with directly. surely this would be a common enough problem that there must be a helper macro in the stdlib that lets you convert between inline and closure iterators? nope, there isn't. okay but writing one should be trivial, right, given the vaunted metaprogramming capabilities of Nim? well, I tried writing one in the most obvious way. and it behaved differently when I used UFCS vs not. and when I experimentally called it on a closure iterator (expecting it to be effectively a no-op), the compiler segfaulted. and when I asked about this in the discord, nobody could figure out why it didn't work. later I found an implementation of inline<->closure conversion macro and it was like hundreds of lines of gensym fuckery and god knows what. i don't know why it should be so complicated.

oh and btw, even with the supposedly "first-class" closure iterators, it is impossible to write a generic function like f: iterable[T] -> iterator[T]. you have to use a template. and the syntax for doing it is counterintuitive. and the "iterable" keyword in the function signature doesn't mean what you think anyway. when you ask in the chat "oh my god just please tell me how to do lazy iteration", they say "don't worry it's easy, just use [x]", where x is one of half a dozen mutually incompatible 3rd party libraries, each one expecting you to learn its own mad little DSL that you can't really extend or integrate with normal Nim code. and then you look at the implementation: enormous inscrutable macros, which are that way presumably to work around all the crap I described in the last paragraphs and even more I don't know about. I don't want that in my dependencies! the docs don't prepare you for all this complexity; templates/macros/iterators are documented like that "draw the rest of the fucking owl" meme.

the "sugar" module has a macro to let you write lambdas more compactly. but if you try to do something straightforward like pass one into sort() as a comparison function (ie the kind of stuff that comprises 95% of the legit uses of anonymous functions in grugbrain code), it doesn't fucking work reliably. like it will probably work on a simple case like sorting a bunch of strings by their length, but the minute you introduce some complication like generics it all falls apart and the compiler spams ten pages of indecipherable type errors at you. and then they'll say "just use sortIt" -- no, fuck you, i will never use sortIt, i hate anaphoric macros, just let me pass in an honest function.

what I'm getting at is, you know how frictionless it is to sling around iterators and generators and first-class functions and so on in Python, even with mypy --strict? and you read about Nim's UFCS and macros and generics and you think "great, best of both worlds", imagining yourself as a ninja doing "myfile.txt".lines.map(func1).filter(func2).max(key=blah).frobnicate, and it all Just Works[tm]? well the reality is as frictionless as dragging your face across raw asphalt.


> what i'm saying is >90% true so i don't care if anyone nitpicks this

Can't argue with that logic :-P You've obviously spent years writing nim and know what you're talking about /s

But in all seriousness, as the author of the sugar.collect macro, I am fond of it. I understand that not everyone likes how fp is done nim but it's ok.


thanks for the work you do! my comment was very harsh, but I would never have written such a long comment if I didn't fundamentally like what Nim is trying to do. it comes from disappointment, not dislike. fwiw I've put in maybe 100 hours honestly trying to learn and use the language, and I don't have much to show for it. I think that has to count as some kind of failure, of the language and/or the documentation. I haven't run into this with any other language.


Thank you for your kind words sir. I didn't expect it. And I am sorry for your lost time. But I hope the situation improves.


> how fp is done nim

It's great that a composition of libraries (sequtils, sugar, algorithm) can get us close to the effortless quasi-FP people may be used to from LINQ. I just wish this would be merged into one library. Pretty much every single module that uses one of them imports all three in my code. We need one, consistent, awesome library to interact with collections.


is it true that I must use GC if I use stdlib of Nim, which by default most people will need its stdlib, how does that translate to c/c++/js when a GC is involved(c/c++ does not have GC)


The GC is a set of data structures and functions which are included in the compiled C/C++ source and which are called by the generated code.


is this production ready? last time I checked GC for c and c++ and I don't think c and c++ are really GC-friendly by design. After nim's transpiling, is c/c++ using those data structures and functions somehow to manage resources(similar to RAII) but not really acting as a GC in c/c++?


Nim offers a choice of several GCs:

https://nim-lang.org/1.6.0/gc.html

for upcoming v2: https://nim-lang.org/docs/mm.html

Note that beginning with v1.6.2 it's specified with `--mm:[choice]` instead of `--gc:[choice]`, though the latter still works.

And beginning with v2, the default GC will be orc, while to date it's refc. That's an important change and has involved a lot of hard work by maintainers and contributors leading up to the release of v2.0.0.

See also the user guide for Nim's compiler:

https://nim-lang.org/docs/nimc.html


C and C++ both have very popular GC libraries which fulfill much the same purpose and even have the same design (the optional Boehm GC, for example). Those are likely good examples to look at to see how managed memory might be invoked by the Nim compiler. Alternatively, if you're using reference counting, that's simply C++'s preferred style (std::unique_ptr), as you already said. I can't speak to whether Nim's compiled code is using std::unique_ptr or something else.


Nim treats C/C++ as portable assembly, so you should think more in terms of compilation than "transpilation". While it can use C gc's like Boehm, it can also use the new ORC that benefits from optional lifetime annotations like `lent` and `sink` to optimize out reference counting, making it more similar to Rust or C++ smart pointers for example.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: