Nim Programming Language

Created: by Pradeep Gowda Updated: Feb 27, 2024 Tagged: programming-language · nim

NOTE: nim was previously known as nimrod.

A quick look at Nimrod programming language

This is a short intro to a fun, productive language called Nimrod.

Nimrod is a new programming language developed by Andreas Rumph.

Nimrod is a statically typed, compiled langauge.

What kind of language is it?

There are few things more irriting than a programming language or library webpage that doesn’t show how the syntax/typical usage looks like. So, let’s see how Nimrod code looks like:

# compute average line length
var count = 0
var sum = 0

for line in stdin.lines:
    count += 1
    sum += line.len

echo "Average line length: ",
if count > 0: sum / count else: 0

The var keyword is familiar if you have used C#, which essentially means that the variable count has an implicit type. That is, you don’t have to explicitly mention the type, in this case an integer.

The for loop line reads naturally for the Python programmer, including the : starting a new block.

Nimrod is inspired by many popular languages old and new. It is quite easy to read and understand what is going on.

According to Araq, the creator of Nim:

Macro system inspired by Lisp.
Export marker taken from Oberon.
Argument passing semantics taken from Ada.
distinct types inspired by Ada.
Syntax also heavily influenced by Python.
Generics inspired by C++.
The 3 pointer like types ptr, ref, var taken from Modula 3.
async / await stolen from C#.
let taken from ML.
...

One could also argue that Nim is a statically typed Lisp with an
infix syntax extended by essential features necessary for
systems programming. And dumbed down to support efficient
compilation to C (where are my continuations?!)..

How to install it?

Checkout the code from github

$ git clone git://github.com/Araq/Nimrod.git
$ cd Nimrod
$ git clone --depth 1 git://github.com/nimrod-code/csources
$ cd csources && ./build.sh
$ cd ..
$ bin/nimrod c koch
$ ./koch boot -d:release
$ ./kock install $HOME/nimrod

This installs nimrod under $HOME/nimrod. Add $HOME/nimrod/bin to the $PATH.

What is the performance like?

Nimrod compiles to C, so you can expect C-like performance (hard performance numbers are a game of benchmarks and nobody ain’t got no time for that…). To go with Nimrod’s authors’ own word “it is performant for ‘soft real time’ systems like games”. Take it as you may.

For me, Nimrod is a vast upgrade over dynamic languages like Python and Ruby without sacrificing a whole lot of expressiveness.

What are some of the quirks

By looking at examples and reading applications/libs written in Nimrod you would not guess it, but nimrod is case insensitive. That is var hello and var HELLO and var HeLlo are treated as the same by the compiler. Where nimrod takes it one step ahead is it’s treatment of underscores, which means var H_E_l_lo is same as var hello. This might appear crazy, but this removes the entire bikeshed argument about which style of variable naming is best.

The nimrod programming community has it’s own best practices for variable names, for instance, new types are declared as TFoo an inspiration from Pascal.

A quick tour of the command line

To compile a nimrod file foo.nim, you type

nimrod c foo.nim

which will give you a foo executable in the same directory, assuming there were no compilation errors. You will also see a nimcache directory.

This directory contains the intermediary C files generated.

What are the resources to learn more

The website: http://www.nimrod-code.org The forum: http://forum.nimrod-code.org – this is probably the best place to get your questions answered. You may also want to try the IRC channel #nimrod on FreeNode.

How can I use Nimrod?

For a young language like Nimrod has not managed to corner itself into any one niche.

Nimrod has been used to write:

  • web frameworks – Jester, a sinatra like framework.
  • web applicatins –Nimforum.
  • build farm – Nimbuild, that builds the nimrod compiler and related tools on major platforms.
  • GUI programs – Aporia, an IDE for nimrod

Personally, I have been using nimrod to replace a few of command line python applications that process large amounts of data.

Standard libraries

Nimrod’s standard library has XML, CSV, Web, String, Regular expressions, OS, Database drivers, Network programming and more…. It also has wrappers to popular C libraries like X, GTK, pcre, cairo, sdl, OpenGL etc.,. Nimrod libraries have you covered for day-to-day programming needs.

Web development

Editors and IDEs

Emacs has a nimrod-mode. A Nimrod specific IDE called Aporia built using the GTK toolkit. I haven’t used it much beyond installing it because I prefer using the Emacs nimrod-mode.

Packaging and reusing libraries

Nimrod libraries can be installed using the babel package manager.

Download the babel source from github

git clone https://github.com/nimrod-code/babel
cd babel
nimrod c babel.nim

After successful compilation, copy the babel executable to a directoy in your $PATH. I put it under $HOME/nimrod/bin along with other nimrod executables.

Distributing applications written in Nimrod

A .babel file is required at the root of your application source directory. Take for example the jester.babel file that is part of the Jester web framework distribution” –

[Package]
name          = "jester"
version       = "0.1.0"
author        = "Dominik Picheta"
description   = "A sinatra-like web framework for Nimrod."
license       = "MIT"

SkipFiles = "todo.markdown"

The file is self explanatory. See the babel.babel file of babel for additional configuration options (eg: executables).

Once you have the babel file in the directory, running babel build will build binaries.

Cross Compilation

From SO

I was having the same issue getting nim to compile executables for Windows, from a GNU/Linux machine, so I made a bash script. It takes the path to the directory containing *.nim source files and the name of the executable file to output. I’m sure you could swap out the GCC compiler (MinGW in this case) and change the --os: switch as appropriate:

#!/usr/bin/env bash
# Nim must generate C sources only, to be fed to MingW
nim c --cpu:amd64 --os:windows --opt:speed --embedsrc --threads:on --checks:on -c -d:release $1/*.nim
# Copy nimbase.h so MingW32 can find it during compilation and linking
cp /opt/Nim/lib/nimbase.h $1/nimcache/nimbase.h
mkdir -p $1/bin
cd $1/nimcache && x86_64-w64-mingw32-gcc -save-temps $1/nimcache/*.c -o $1/bin/$2.exe
rm $1/nimcache/*.{i,s} # only care about *.o objects
ls -lAhF $1/nimcache
ls -lAhF $1/bin

Books

Tutorials

Interop (FFI)

Nim+D

Testing

Compile time

Libraries

Web development

Dev tools

Random notes

Nim’s GC is per thread: You can easily have threads which are hard realtime and don’t use the GC and happily use the GC in the other threads… And the type and effect system ensures you don’t mix these different per thread heaps. – Araq

[Nim has] C++-like features (generic types, operator overloading, function overloading, inline functions, optional O-O, optional data hiding, C pointers, bitwise-compatibility with C, your choice of manual memory management or GC) and C++-like run-time speed, combined with Python-like syntax and compile-time Lisp-like macros. – HN comment

GC free Nim programming

The no GC future is --gc:stack which replaces the GC with memory regions. So any library that uses the GC really uses a memory region. The entire situation is ok. Note that the GC is always thread local anyway, so you can also just run realtime threads with other threads that use the stdlib and thus the GC. – Araq

use these: alloc, dealloc, allocShared, deallocShared. You can cast the pointer from and to ptr types and then you have your manually managed heap memory. (This is a general answer to how to use non-GC’d memory and has nothing to do with memory regions) – flyx

A good example of using FFI in nim in comparison to D and rust.

Discussion in /r/python about a nim article.


From a reddit thread: What problem does Nim solve?

Low friction, high performance development.

It feels like a scripting language in terms of writing code rapidly. Deferred GC means no need to worry about memory (although easy to manually manage it). So, a sort of statically typed, compiled Python with C-level speed and tiny, self contained executables.

High level AST metaprogramming that lets you hygienically extend the language, has static typing with inference and uses structural typing for generics which often means you don’t even need object hierarchies, extensive compile time evaluation (to the point you can process files, create hash maps or pull web data by simply defining your desired variables as ‘const’).

It compiles to C, C++, LLVM (experimental), and Javascript. Excellent FFI so you can use all the C, C++ and JS libraries as well as Nim ones. Very fast compilation that’s going to get faster from what I’ve read about future plans.

This may be subjective but I also like how clean it looks. Few $!;@ symbols and easy to read.

Personally, it’s brought the fun back into development for me.


Stack vs GC vs Manual memory management

  • type Foo = object -> Value type, on the stack
  • type Foo = ref object -> Ref type, managed by GC
  • type Foo = ptr object -> Pointer type, manual memory management (malloc, free, memcopy …)
  • Pointer arithmetic can be achieved using casts. via

Stack vs Heap from a Reddit thread:

By PMunch:

First order of business heap vs. stack: Whenever you call a function it creates a stack frame. Stacks are simply said first in last out, so when a function call is done it pops it’s frame from the stack, and you return to the previous frame. When you declare a variable inside a scope in is typically allocated on the stack. This means that when the function returns that part of memory is not in use anymore and the value is gone (technically it’s still there, but we shouldn’t try to access it). The heap on the other hand is quite a bit different. Items on the heap are allocated and live there until you deallocate them. In C this is done manually with calls like malloc and free. In Nim however, and C# for that matter, we have the garbage collector (or GC), this nifty thing reads through our memory and checks if anything still points to things allocated on the heap and if nothing is pointing to that which was previously allocated it gets free’d. This means that we won’t leak memory as easily as you would in C as things that we’ve lost every reference to get’s automatically cleaned. Okay, now that we know where our stuff lives in memory, let’s look at how Nim represents those things. Basic types are things like integers, floats, bools, and characters. Their size is known and static. Nim also calls strings a basic type, but those are not quite like the rest since they can change in size. Since our stack is first in last out it means that it makes sense to store everything in order. But storing things in order isn’t possible if you want to change the size of something (for example appending to a string). So when we create numbers in our Nim code they will be stored on the stack, this is why you never need to free your numbers and don’t have to set them to nil when you’re done with them. So what are types? In Nim you can create aliases for types like type age = int this is just a way to say that age is an integer, and it will be treated like one for all intents and purposes. If we want to create collections of types to represent something particular we can create objects, don’t think of these quite like objects in an object oriented language, think of them more like structs in C. Such objects are simply a collection of values. So in Nim when we create an object it will live with us on the stack. If we return an object it will be copied to our caller, and if we insert it into a data structure it will also be copied. While this might be practical in many cases (even offering a speed benefit if done right) we often don’t want to copy our large objects around. This is when allocating on the heap comes into play. If we define our type as a ref object it means that the type is actually a reference to an object. I’ll come back to the difference between a reference and a pointer later, but for now just remember that a reference is the memory location of an object on the heap. This means that if we return a ref object it means that we’re only returning the memory address of that object, not copying the object itself. This also means that if we insert it into a data structure only the reference to the object is inserted. Whenever you see new SomeObject it means that it allocates memory for that object on the heap, and gives us a reference to this object. If we had simply done var myObject: SomeObject and SomeObject was defined as a ref object we would only have a reference on our stack, so trying to access it would crash saying we had an “Illegal storage access”. This is because Nim defaults our value to nil, and no-one is allowed to access memory area 0. So imagine we had an object that contained the height, the weight, and the age of a person. That could be represented by three integers. If we wanted to return this object it would mean copying all those three values to our caller. If we defined it as a reference, we would only pass one integer, the position in memory (on the heap) where we stored the three others. Conveniently this also means that if one functions modifies a value in a referenced object, that change would be visible for all other functions using the same reference (since they all point to the same place in memory). This is practical for example if you want to make one list sorted by age, one by height, and the third by weight. Instead of copying our person three times, we could just use three references, one in each list. So now that we know where and how are values are stored we can look at the difference between a pointer and a reference. In pure Nim code you would typically only use references, these are what every call to new creates and what goes on behind the scenes most of the time when working with strings. A reference is also called a managed pointer, it simply means that Nim manages this area of memory, and that it will be automatically free’d for us by the garbage collector when Nim sees that we’re not using it any longer. Pointers on the other hand are unmanaged meaning that Nim doesn’t try to do anything with the memory behind that pointer, most of the time you won’t even know what is there. The reason there are pointers in Nim is mostly to interface with C. In C every time you want objects on the heap you need to manually malloc and free them. Many C libraries work by passing around a pointer to a structure containing some state and all good libraries have some way of dealing with this memory. Typically you do it by calling some initialisation function when you begin and then some cleanup function when you are done. In Nim we might want to use a C library such as that, but since we might loose the reference in our own code while the library still keeps a reference somewhere which Nim doesn’t know about we can’t have a reference to it as Nim would garbage collect it. So instead we have pointers. I hope this made it somewhat clearer, if you want more examples or if anything was unclear, feel free to ask.

Benchmarks

Talks

Editors

Visual studio Code

Nimlime

Nimlime is a plugin for Sublime Text the provides Nim compatibility. This is my custom settings overriding the default settings:

{
    "nim.executable": "/Users/pgowda/src/Nim/bin/nim",
    "nimble.executable": "/Users/pgowda/.nimble/bin/nimble",
    "nimsuggest.executable": "/Users/pgowda/.nimble/bin/nimsuggest",
    "provide_immediate_nim_completions": true,
    "output.send": false
}

The output.send option set to false is an important one; withtout this, the plugin would create a new compiler output buffer everytime the file is built, which is everytime I saved the file!.

Blogs

Code

Code to read etc.,

Eventually I decided, that being able to do transformations on the AST (abstract syntax tree) of the programming language would greatly help to develop this toolbox. I tried out Rust, but I quickly found out that their macros are too weak to even implement println, and I had to look somewhere else. (At this point in time Rust also has procedural macros, but they still don’t appear to be powerful enough to do the things I need to do for this project). Eventually with Nim I finally found a language that suited my needs. It has AST based macros, arbitrary code execution at compile time, static typing, reflection and a lot more.

News

See also: Crystal, Interesting Programming Languages, D, Python, Rust.