Nim – Python-like statically-typed compiled language
nim-lang.org
nim-lang.org
I know it's chicken or the egg but I have real problems choosing these languages when they just aren't as battle hardened or package wise versatile as say python or ruby when making decisions for my own tech stacks in a startup or for other companies I have or will work for.
Arguably a really nice benefit of these languages is the inline error highlighting, which speeds up development. I've found for Nim and Crystal I have to run the compiler in the terminal, look where the errors were, and then find those lines in my editor.
LSP support is minimal ( especially when a language is starting out ). My ideal editor for Nim would be Pycharm-like ( open source edition ) with an LSP backend.
I pretty much do this with any language I use, including C++ or even Java and Kotlin. I just use vim for everything, it makes it easy to switch around between languages without dealing with a new IDE, and I haven't used any autocompletion in any language in probably 10 years -- that aspect is over-rated.
Vim, for example, has a plugin called "syntastic" that is kind of a meta-plugin aggregating lots of these, and indeed it seems to have support for nim error checking.
LSP is a nice step forward, but people had error highlighting for decades before it was invented.
[edit]
Doesn't change anything above, but someone pointed me at ALE which is a newer tool that can run lint engines asynchronously (using interfaces that didn't exist when syntastic was created). For vim specifically that may be a better tool, but I haven't tried it yet.
That's true, but being able to quickly click on the line that has the error and have your editor navigate to the file automatically is slightly more painful to setup, and is bespoke for whatever tool you are using.
My point was just that a tight integration between language and IDE/editor makes the overall language experience much nicer. For example:
Racket/Dr. Racket Python/Pycharm Java/Intellij Emacs lisp/Emacs
In the event that the tool doesn't output in one of the common formats, it's usually just a regex; again I had this in Vim for several different languages back in the 90s.
>> My point was just that a tight integration between language and IDE/editor makes the overall language experience much nicer.
I agree (happy SLIME user here), but it often seems like I'm in the minority. I've literally never met someone in person besides me that uses pycharm, and you are about the 3rd person online I've seen mention it in a favorable light.
I was working on integrating a language with a "programmers editor" <name omitted to protect the guilty> and asked how to extend the editor to indent a new language. The response was "it should already support all C/Java like languages with the configuration format." My response "this isn't a C-like language". The community response "Uh, I guess write a plugin that installs a hook on the carraige-return key and manually position the cursor?" It blew my mind that anything billed as a programmer's editor couldn't be customized for doing this already...
The syntax compilers use to indicate filename and error location are similar among compilers, and generally quite unambiguous anyway, so in many cases no configuration is needed. A small list of regexes built in to the editor is enough.
To be fair, I dont actually know what percentage of editors have that feature, my impression is just that many people arent aware of the idea. Maybe Im wrong though.
Perhaps its because the product I work on is fairly mature at this point, but "speed" isn't something I really optimize my workflow for.
It's much more important that I solve the right problem than that I solve "a problem" quickly.
When the lifetime of the code you write is measured in years / decades, saving minutes seems much less relevant.
I found that tight language integration to the IDE/Editor makes jumping into new code bases in the language much easier. I've found refactoring also becomes easier.
So I guess I agree with you that for the very common programming task of "Thinking about the problem" tight language integration doesn't help much. But in order for me to gather data points about the problem, I usually have to jump in and explore the code base, which is where I feel the advantage comes from.
Definitely setup your editor to run the compiler for you, and give you a list of errors that are links to the locations they occur.
In Vim, for example, you can configure the makeprg and errorformat variables and the use the :make command to run the compiler, which populates the quickfix list with the errors. From the quickfix list you can jump directly to the locations. In Emacs there is the M-x compile command with very similar functionality.
The object-oriented and high performance features of C++ make it a good match for games. Seems to me this makes Rust a fairly natural choice for high-performance games in future.
If you look at Unity, although the games are written in C#, there is a heavy emphasis on mixins for giving functionality to game objects, rather than inheritance or interfaces.
Between mixins and the ECS pattern, I think Rust's trait-oriented style looks aligned with that trend.
Python seems like a very popular choice when the time comes to replace bash or perl scripting from the 90s. Oodles of internal tooling and OS tools in the Linux space use it.
TCL designed at Sun, pushed on the Web early days with application servers like AOL Server and Revit (or something similar have forgotten the name).
Perl was introduced in UNIX since the early days and was the tool to use when sed and awk scripts got too complicated.
Ruby was made famous thanks to Rails, and gets very little use outside Rails.
Lua, used as scripting language in a couple of game engines, made famous via World of Warcraft.
Instead of this pondering and retroactive application of intuition in one's head onto history it would help to learn history. (Hint, what is GNU's name)
For me it makes compiled languages fun again. I like rust but package maintenance gets rough.
Things like this are what I'm enjoying discovering: https://robert-mcdermott.gitlab.io/posts/speeding-up-python-...
Crystal looks nice too, but I want code that compiles to C/C++, not llvm for embedded work.
Not sure about Crystal, but I’ve been able to find all the packages I needed for embedded and even some ML work. That Nim can wrap C/C++ libraries really helps there, otherwise it’d be a pain. For example I wanted to load PNG images, well someone wrapped a C library [1]. Or to create Elixir NIFs (with exception safety!) [2]. Generally if there’s a C/C++ package it only takes a few hours to wrap and use.
Nim has some annoying parts, like understanding the ref/var distinction and lack of examples. The documentation is fairly complete otherwise.
1: https://github.com/define-private-public/stb_image-Nim 2: https://github.com/wltsmrz/nimler
Python is the ultimate glue code scripting language, but you can't build a performant algorithm without an efficient C implementation underneath. With languages like Nim taking performance seriously, people could build a complete implementation of such algorithms from the ground up.
This doesn't just mean the core implementation would be easier to maintain. There's a huge gap between people who use the python libraries and people who build the efficient code that runs underneath. This clear division between those two worlds is what makes it difficult from people to jump from one side to the other, and that's why I'm calling this gatekeeping.
Not necessarily Nim, but using a performant, simple high level language for this sort of tasks would blur this divide. In practice, this means AI researchers in universities could dive into the code that's actually doing the work, not just play with the toy buttons and levers Google and Amazon left for them to play with.
Nim is compiled into C, IIRC, but it uses Nim syntax and rules and you don't call it "C". Same way, Python's Numba is compiled into LLVM IR at runtime, and you basically write Python, with a few limitations. You don't have to write or know any C/C++ to write high-performant numeric algos in numba (just clarifying) and there is no "C implementation underneath" as you're saying. It's also one of the easiest ways for "AI researchers in universities to do the work" because they and their friends probably already know Python but not Nim.
Re: ML libraries like lightgbm and many others - they are written in C++ so that there's a public C FFI which can then be wrapped in other languages, and not only in Python. This is probably the most flexible way to do things as opposed to limiting the whole thing to one niche/language.
// I'm not saying Nim is bad, Python is good, or any of that - I like alternative languages myself, but being an "AI researcher" and practitioner and spending most of my work time on developing numeric ML algorithms, I'd never look into Nim for doing any serious work, at least not now, partially because then I'd be the only person maintaining whatever I write alone and forever.
I still stand by my comment, though. We need to discuss technology by its own merits. Of course I'd also choose Python for an ML project any time of the day! But that's because Python won the popularity contest a long time ago. When discussing technology I think it's worth trying to see past that.
Exposing a C FFI may be flexible in the ways you mention (i.e. You can call the function from many languages). But I think we miss a lot on explorability. Let me elaborate a bit more with an example: Most people is not reallistically able to drill down on some implementation details when using neural network libraries like TensorFlow (which is not the whole field of AI, just an example!). At some point, if a feature is missing, you have to leave Python, learn a new language, and get a whole dev environment setup started. At that point, you're not using Python anymore, so I don't think it should count as a Python merit that you can do it.
That being said, I don't know Nim enough to validate whether using it for this would be a good idea.
One trick that works as a guarantee for me is writing Nim code in almost pseudo-language style, which in theory will be easier to port to other languages, it's very easy to do.
1) Language is sponsored by tech giant or
2) It slowly evolve over period of 15-20 years, provided enough people see usefulness even in face of lacking features/libraries/tooling etc.
But then I got to the home page and saw “fund crystal and help make it production ready” and felt like it wasn’t a risk for something I needed to get out the door.
I did build a small toy project in Crystal and really enjoyed working with it.
I found it easy to get up to speed and do something useful with it. The language is also in my opinion very readable. The documentation could use some more (larger) examples though.
For this wrappers tool I needed a front-end for which I wanted to create an interface with argparse. Unfortunately the standard library lacks an implementation, and third-party packages did not deliver what I needed. In the end I wrote that part in Python still.
The biggest issue I currently find is the lack of a lock file format for its package manager. It's being developed, and as soon as its there I intend to implement support for it in Nixpkgs. https://github.com/nim-lang/nimble/issues/127.
The compiler gives very useful output and is fast as well, and the generated binaries are small. I like this language!
One thing I noticed right away that it seems to be lacking (judging from the `nimph.json` assuming that is the lock file) are checksums over the data or hashes of revisions the references correspond to. References such as tags are mutable, and thus hashes are needed to validate them. See e.g. the discussion over at https://github.com/NixOS/nix/pull/3216.
Reality doesn’t work like that, of course. Hype is important, and not just because that will mean more libraries. Hype motivates people to do things they wouldn’t have otherwise done at all. Rust demonstrates this well.
And good multithreading and network libraries.
Python has strong types. It's just that it checks them at runtime, not before.
If you don't use MyPy or similar, anyway.
Common Lisp allows for type inference and some compilers use that to various degree, as well as to declare a type of a given symbol (or the signature of a function). Depending on compiler and optimization settings, that information is then used to generate optimized code, much like a compiler for a (weakly) statically typed language would or detect mismatches. SBCL is probably one of the most advanced Common Lisp compilers in this regard.
class Testing123:
def __init__(self):
self.blah = whatever()I see a pattern of sorts for some new(ish) languages: without a prominent, well-known sponsor, the language might struggle to gain attention among developers. I wonder what will be the fate of other languages without generous sponsors as they head to their version 1.00 e.g. Crystal or Zig?
Julia is doing relatively well without a big main sponsor - interest seems to be growing in the language.
Rust and Go are two languages that have benefited hugely from support from Mozilla (Rust) and Google (Go).
But back to Nim. Who's using Nim? What are you using it for and how are you finding it?
I am using it for game and music programming: https://github.com/paranim
Only been using it since the beginning of the year and it is fantastic. Much less development friction than rust, and perf is very good, especially with ARC.
Also for linear algebra and machine learning they're a couple of good libraries:
1) Arraymancer https://github.com/mratsim/Arraymancer
2) Neo https://github.com/unicredit/neo
3) my own :) not meant for when performance is required. https://github.com/planetis-m/manu
https://www.youtube.com/playlist?list=PLxLdEZg8DRwTIEzUpfaIc...
If for some reason the nim compiler starts becoming slow, then this could also drastically speed up development
https://github.com/nim-lang/Nim/blob/cd28fe2ef7a204721efa720...
It's calling `quit` which cannot be caught in a try statement.
Also, Nim seems to be targeting a different niche from Python. As Nim is statically-typed and AOT-compiled, its closest competitor is probably Go. The difference is that Go deliberately tries to be a simple language, while Nim is much more complex.
However for me Nim appeared simpler when starting out. Not much get in your way when prototyping and scripting. Other languages require some mental overhead. I'm referring to Go's error handling, Java's mandatory exception handling, Rust's tracking lifetimes, etc. Thus it's much more pleasant to use than the rest.
And to be perfectly transparent, I know relatively little of Go. My impression is that nim has more features in general, which could be considered to make it more complex. That can be a good and/or bad thing depending on perspective.
I think that authors of Nim libraries get so tied up in their superiority over having types and being compiled that they forget that most devs don’t really care about these things on their own. It’s only when these things are combined with good documentation and tooling (see Rust for example) that they become useful.
So here's a simple project I wrote that's easier to understand. I work on this every couple of weeks on Saturdays.
https://github.com/sergiotapia/torrentinim
For example: parsing html https://github.com/sergiotapia/torrentinim/blob/master/src/c...
I wish the Nim team worked on an easier onboarding process to the language. The documentation is in depth but it just throws everything it has at you all at once with no progression.
This sums my experience as well. But nowadays there are more resources to learn Nim. The Nim in action book is a few years old but still holds. Nim basics is a free tutorial for beginners https://narimiran.github.io/nim-basics/ When did you start learning Nim?
However, it's just a wall I haven't really bumped into. I suspect many people don't, and a part of that is popularity - so much exposure can do a lot to expose the warts. Though I think that goes for both Julia and Python.
But I think once you know numpy well you probably won't run into that restriction (can extend in the native python) unless you're an expert (for the ML usecase).
Rust does it too, calling external unsafe code so they don't need to rewrite the world all in one go. I'd say that the extendability of a language isn't just fair, but a crucial aspect in comparing languages because that's what people do in the real world.
It's a real shame because Julia initially felt like it might develop to be the natural successor to Python in scientific computing, but over time that has seemed less and less likely.
Main problems were cryptic errors in the REPL, super slow start-up and first run times (JIT issue I seem to recall reading was being improved), and a generally very poor third-party package management system.
On the last issue, I'd say Python is not perfect but pip and various virtualenv management systems are "good enough". Having something like the Rust/Cargo setup is what I would prefer.
Popularity is a good enough proxy for how good a given tool is at a given task. Go give 100 people a hammer and a tootbrush and ask them to nail a plank, and you can divine the relative usefulness of each tool based on the number of people who used each.
> As for the second, nobody has to prove anything to you
Nobody is beholden to anyone, but if you're putting a contrary position forward with no evidence be prepared to be asked to elaborate. Such is life.
Then no doubt the majority of those 100 people would use the toothbrush to hammer the nail. It is after all a far more popular tool.
Then you have PHP, which is (or at least was) an inferior langauge to Python when python started getting popular. Python does more that just web dev. Likewise with Ruby.
Python could easily be described as "better" depending on the task.
Even something like inverting a random 4x4 matrix is just so much simpler. In julia it's just "inv(rand(4,4))". In python, you'll have to install numpy first and then writing it out is like 4 times as many characters.
And yeah, you need to install numpy first. But if you're doing this work you of course already got it installed.
import numpy as np np.linalg.inv(np.random.rand(4,4))
And you have to write it like this, because of lack of dynamic dispatch.
> np.linalg.inv(np.random.rand(4,4))
Which of course is nothing to do with python, and is trivially reduced to the aformentioned `inv(rand(4, 4))` with imports.
> And you have to write it like this, because of lack of dynamic dispatch.
Not at all.
Dynamic dispatch would help if you also defined a "rand" function in scope, but that's a way more general argument and IMO you'd lose more than you gain with it.
I still went with Rust in the end, though. Nim’s documentation was rough going and I hit a lot of walls. The initial learning curve for Rust was way higher (borrow checker and all that) but once I got up to speed it was a great experience.
With both Rust and Python you have "access" to C FFI. (Not the C++ out of the box but there's some projects out there that make it work)
[1]: https://conf.nim-lang.org/
Hacker news coverage: https://news.ycombinator.com/item?id=23585006
Cython is a superset of Python that allows super easily compiling custom Python extension modules directly in C or C++, interoperates easily with Python packaging, and is very battle tested.
It allows you to “just write for loops in native Python” and get the statically typed & compiled optimizations you’d get in C or C++ for free. It also supports fused types for multiple dispatch of compiled functions.
I’ve used it in production workflows at many companies. It’s very easy to use.
The best part is that you can apply it gradually, only bothering to implement small sections of code as Cython extension modules when there’s real proof from a profiler that the code is a bottleneck for reasons addressable with static typing. You don’t have to live with the huge premature optimization baked in as a premise to languages that enforce this for all code. “Static typing when _you_ need it.”
> Numba translates Python functions to optimized machine code at runtime using the industry-standard LLVM compiler library.
Anything like coroutines, async-await etc? Or just OS threads?
What might those "pretty" "simpler tools" be? Perl? Heh.