Systems Programming with Nim

Nim is a statically typed compiled systems programming language. I’ve seen a few posts about Nim popping up on HackerNews recently and was curious enough to give it a go.

My go-to tool / application to implement when trying out a new language these days is a simple CLI tool.

Recently I had a go at trying Rust – creating fstojson-rust. Sticking to systems programming languages, Nim came up next.

Here are the things I initially liked about Nim:

  • Statically typed, compiled language.
  • The Nim compiler and generated executables work on all the major operating systems. i.e. Linux, macOS, Windows, BSD.
  • Lots of documentation and tutorials.
  • An online Playground.
Some Nim code in my IDE
Getting started with Nim

Getting Started With Nim

Installation is really simple regardless of your OS. On macOS I chose to run the choosenim installation script. (Remember, always check and inspect scripts that you cURL / run directly from online sources):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
curl https://nim-lang.org/choosenim/init.sh -sSf | sh
curl https://nim-lang.org/choosenim/init.sh -sSf | sh
curl https://nim-lang.org/choosenim/init.sh -sSf | sh

You can also download pre-built binaries for your OS at the main Nim Download page, or use a myriad of other methods to get it running such as Homebrew, Docker images, etc…

Nimble is a package manager that is bundled with Nim (since version 0.15.0). It is very similar in what it does as what npm does for node for example.

If you wanted to upgrade nimble itself, you can simply do:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
nimble install nimble
nimble install nimble
nimble install nimble

Just like an npm update!

To create a new project, you can use the init command. An interactive CLI wizard guides you through creating a Library, Binary, or Hybrid project type.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
nimble init [pkgname]
nimble init [pkgname]
nimble init [pkgname]
nimble init guide for new projects

A Nim project can use a .nimble file, which is equivalent to package.json in the Node.js world. Nimble is used to work with the project’s .nimble file.

To check the validity of your project and dependencies, you can run the check command:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
nimble check
nimble check
nimble check

Then to install a new package you use the install command with nimble (the default is to install latest, but you can also install a specific version of a package, e.g. one from a git repository):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$ nimble install package@#head
$ nimble install package@#head
$ nimble install package@#head

Getting Acquainted with Nim

I started off with a really simple program that simply reads from stdin and then echos back a message.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
echo "What's your name? "
var name: string = readLine(stdin)
echo "Hi, ", name, "!"
echo "What's your name? " var name: string = readLine(stdin) echo "Hi, ", name, "!"
echo "What's your name? "
var name: string = readLine(stdin)
echo "Hi, ", name, "!"

Building and running locally is simple. You can run nimble build or nimble install. The build command will create a debug version of your program which includes stack traces, while install will create a release version.

You can also pass Nim flags to these commands, though for anything permanent you can add a configuration file and specify them there.

You use nimble run to build and run your program in one go.

There are many more command options available for nimble. Just run the command without anything else to access the list.

fstojson-nim

Next, I jumped into writing my go-to application for traversing the file system and collecting directory and files in a designated path to output to a JSON hierarchy.

You can take a look at my code in GitHub.

My overall experience was that I found Nim to be a lot more foregiving in terms of safety checks and recursive functions than what Rust was.

I was able to use a single function (in Nim these are called procedures and are defined with the proc keyword), which could recursively call itself for traversing a nested directory hierarchy.

I created a simple object (PathObjectNode) which would store the information about each file or directory, with a children property that is used to hold a list (seq) of more PathObjectNode objects if they object is a directory (files of course do not have children).

A single hierarchy is created at the start of traversal and all directory or file object nodes are added to this.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
var hierarchy = newSeq[PathObjectNode]()
var hierarchy = newSeq[PathObjectNode]()
var hierarchy = newSeq[PathObjectNode]()

At the end of traversal I simply echo out the JSON representation of the root hierarchy node (along with all children). Optionally, this can be prettified JSON.

Speaking of options, I used a handy package called docopt to provide the CLI interface. It was a case of simply adding this to my project’s .nimble file dependencies.

The interface can then be specified by providing a docopt string. For example:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
let doc = """
traversefs
Usage:
traversefs [-p | --pretty] [-r | --recurse] PATH
Arguments:
PATH The path to begin traversing
Options:
-h --help Show this screen.
--version Show version.
-p --pretty Pretty print JSON
-r --recurse Recusively traverse paths.
"""
let doc = """ traversefs Usage: traversefs [-p | --pretty] [-r | --recurse] PATH Arguments: PATH The path to begin traversing Options: -h --help Show this screen. --version Show version. -p --pretty Pretty print JSON -r --recurse Recusively traverse paths. """
let doc = """
traversefs

Usage:
  traversefs [-p | --pretty] [-r | --recurse] PATH

Arguments:
  PATH          The path to begin traversing

Options:
  -h --help     Show this screen.
  --version     Show version.
  -p --pretty   Pretty print JSON
  -r --recurse  Recusively traverse paths.
"""

With that done, and a simple nimble build later, I could run the binary directly to use it.

Closing Thoughts

Nim feels like an easily accessible systems programming language to me. Although I haven’t really used it enough to have an informed opinion, my thoughts are that it strikes a nice balance between usablity, ease of entry, performance, and type safety.

I’ll definitely consider exploring it further for other projects when I get the chance.

Leave a Comment