It's probably been three years since I discovered the Nim programming language. Back then, it had not yet reached version 1.0 despite having been in development for almost a decade. I was intrigued by it's claims and features but didn't take a deep dive.
In the last year I've decided to give Nim a serious try. After spending some time with the language, I've fallen completely in love with it. Nim has allowed me to understand the benefits of certain language constructs and through learning Nim I have also learned to write better code.
Not only has the language itself stabilized over time, but Nim's ecosystem has evolved as well. Today, Nim has shown that it has achieved maturity and should be considered a serious contender for a growing number of use cases.
Nim boasts efficiency, expressiveness, and elegance. It is a statically typed and compiled language with a very ergonomic type system.
The types of all variables are known at compile time and the compiler will not allow you to make trivial type related errors that are so common in dynamic languages where variable types are only evaluated at runtime. This alone prevents an entire category of bugs from existing in code written in Nim.
The Nim language uses
var keywords when declaring variables to differentiate between variables that are immutable and evaluated at compile time, simply immutable, and mutable respectively.
The type system is simple yet flexible and provides semantics for inheritance, distinct types, tuples, generics, and ordinal or sum types.
Nim combines successful concepts from mature languages like Python, Ada and Modula. The overall syntax is similar to Python's as indentation is used to denote blocks instead of curly braces.
An example of the popular cross platform NiGui library which wraps GTK3.0 on Mac and Linux and the WIN32 API on Windows.
An example from the Arraymancer library implementing a simple neural network.
When building native applications, the nim compiler generates dependency-free executables that are small, fast, and easy to distribute.
When building libraries the Nim compiler can generate DLLs or static libraries to be used from other languages.
As a result of Nim compiling to C or C++ it also has incredible interoperability with C or C++ code. There are even a number of tools in the Nim ecosystem that allow you to automatically generate Nim bindings for C or C++ libraries.
The language's standard library is powerful without being overbearing. It provides a large number of data types and modules that you can use to accomplish almost anything you can image. Nim's standard library is closer to that of Python or Node than C. It even provides support for most databases right out of the box.
With the exclusion of the
system module which implements the basis of Nim and is implicitly imported by the compiler, each module provided by the standard library must be imported manually when used. This means you can import only the symbols you use in your modules and prevents namespace pollution.
On top of the functionality provided by the standard library, Nim has a constantly growing community driven package system and an excellent package manager known as Nimble.
Nimble is used to install dependencies from the Nim package directory for use in your project.
In the package directory you can expect to find:
- Web Frameworks
- API clients for many public APIs
- Curses and terminal UI frameworks
- Native UI libraries
- Game engine and graphics programming libraries and bindings
- Machine learning, statistics, and math libraries
- A wide array of community supported data types
- Bindings for a massive number of C and C++ libraries.
- And plenty more.
Seriously, this list just scratches the surface when it comes to the number of packages the Nim community has shared in the Nim Package Directory
Nim has strong metaprogramming features and provides a macro system that can be used to augment the language as needed. The macro system is convenient for abstracting repetitive patterns in your code or building a domain specific language that is actually just Nim code.
Macros are executed at compile time. All Nim code is compiled to an abstract syntax tree by the compiler and it is at this level that macros operate. Nim macros can be used to transform the abstract syntax tree directly and are far more flexible that traditional text based macros.
You can accomplish almost anything in Nim without the need for macros, but they allow you to extend Nim with custom lanuage features when needed.
Nim has truly changed the way I think about building systems and has become one of the most powerful tools in my toolbox as a software developer. It has allowed me to write web applications and APIs with a level of confidence in my code that I otherwise would not have had. It has also acted as a spring board that has lead me to explore 3D graphics programming, neural networks, and embedded systems programming.
My experience with Nim thus far has been positive enough that I've felt the need to share it with the world. Go give Nim a try, you might just feel the same way.
If you are interested in learning more about Nim, the learning page on the official website is probably the best place to start. It contains a large list of both offical and community resources that will get you started.