Nim (programming language)


Nim is an imperative, general-purpose, multi-paradigm, statically typed, systems, compiled programming language designed and developed by. It is designed to be "efficient, expressive, and elegant", supporting metaprogramming, functional, message passing, procedural, and object-oriented programming styles by providing several features such as compile time code generation, algebraic data types, a foreign function interface with C and C++, and compiling to C, C++, Objective-C, and JavaScript.

Description

Nim is statically typed. It supports compile-time metaprogramming features such as syntactic macros and term rewriting macros. Term rewriting macros enable library implementations of common data structures such as bignums and matrices to be implemented efficiently, as if they were builtin language facilities. Iterators are supported and can be used as first class entities, as can functions, allowing for the use of functional programming methods. Object-oriented programming is supported by inheritance and multiple dispatch. Functions can be generic and can also be overloaded, and generics are further enhanced by the support for type classes. Operator overloading is also supported. Nim includes tunable automatic garbage collection based on deferred reference counting with cycle detection, which can be turned off altogether. In 2014, Andrew Binstock said:
"Nimrod ... presents a most original design that straddles Pascal and Python and compiles to C code or JavaScript."
Today, Nim compiles to C, C++, JavaScript, and Objective-C. The goal for Nim is to be as fast as C, as expressive as Python, and as extensible as Lisp.

History

Nim's initial development was started in 2005 by Andreas Rumpf. It was originally named Nimrod and the project was made public in 2008. The first version of the Nim compiler was written in Pascal using the Free Pascal compiler. In 2008, a version of the compiler written in Nim was released. The compiler is free and open-source software and is being developed by a community of volunteers working with Andreas Rumpf. The language was officially renamed from Nimrod to Nim with the release of version 0.10.2 in December 2014. On the 23rd of September, 2019, version 1.0.0 of Nim was released signifying the maturation of the language and its toolchain.

Language design

Syntax

The syntax of Nim is readable, as it highly resembles that of Python. Code blocks and nesting statements are identified through use of white-space according to the offside-rule, and many keywords are identical to their Python equivalents, which are mostly English keywords, where other programming languages use punctuation. Even though Nim supports indentation based syntax like Python, it introduced flexibility whereby one could break statements with a comma or binary operator to the next line. Nim also supports user-defined operators.
Nim is almost fully style-insensitive; two identifiers are considered equal if they only differ by capitalization and underscores, as long as the first characters are identical. Historically Nim was fully case-insensitive.

Semantics

Others

In details, it is influenced by:
Also, Nim supports Uniform Function Call Syntax and identifier equality.

Compiler

The Nim compiler emits optimized C code by default and defers compiling to object code to an external C compiler to leverage the existing optimizing and portability capabilities of the C compiler. Many C compilers are supported including Clang and GNU Compiler Collection. The Nim compiler can also emit C++, Objective-C, and JavaScript code to allow easy interfacing with application programming interfaces written in those languages. This allows writing applications for iOS and Android. There is also an unofficial LLVM backend allowing to use the Nim compiler in a stand-alone way.
The Nim compiler is self-hosting, meaning it is written in the Nim language. The Nim compiler supports cross compilation for other computers/operating systems from a different computer/OS. This is useful for compiling applications for embedded systems or uncommon computer architectures.

Tools

Nimble

Nimble is the standard package manager used by Nim to package Nim modules, it was initially developed by who is also a core Nim developer. Newer releases of Nim come with Nimble included.
Nimble packages are defined by .nimble files, which contain information about the package version, author, license, description, dependencies and more. These files support a limited subset of the Nim syntax called NimScript, with the main limitation being the access to the FFI. These scripts allow changing of test procedure, or for custom tasks to be written.
The list of packages is stored in a JSON file which is freely accessible in the nim-lang/packages repository on GitHub. This JSON file provides Nimble with a mapping between the names of packages and their Git or Mercurial repository URLs.
Nimble command-line tool
Because Nimble comes with the Nim compiler, it is possible to test the Nimble environment by running:
nimble -v
This command will reveal the version number, the compilation date and time and git hash of nimble. Nimble utilizes git, which must be available for Nimble to function well. The Nimble command-line is used as interface for installing, removing, and upgrading/patching module packages.

c2nim

c2nim is a transcompiler/transpiler that helps to generate new bindings by translating ANSI C code to Nim code. The output is human-readable Nim code that is meant to be tweaked by hand after the translation process.

Choosenim

Choosenim was developed by Dominik Picheta, the author of the book , as a tool that enables a developer to have multiple versions of Nim compilers in their machine. Choosenim installs Nim from official downloads and sources, enabling easy switching between stable and development compilers.

Koch

A maintenance script that is used to build Nim and also provide HTML documentation.

Nimgrep

Is a generic tool for manipulating text. It is used to search for regex or peg patterns or search the whole directory at once and also replace tasks.

Nim Suggest

Nimfix

Nimfix is a tool that helps to convert old-style Nimrod code to Nim code. Nimfix is currently beta-quality.

pas2nim

pas2nim is a tool to translate Object Pascal wrappers to Nim code. It was used to translate the original Pascal sources of the Nim compiler. Only what maps easily to Nim is supported. Free Pascal, Delphi-style classes, and some other features are unsupported. At this time, development and maintenance is mostly stalled.

py2nim

py2nim is a tool used for transpiling Python code into idiomatic Nim code. Currently its development is stalled.

Keywords and Standard Library

Standard Library

The Nim standard library can be classified into two groups known as pure and impure libraries.

Pure Libraries

Are a collection of modules written only in Nim without wrappers to access libraries written in other programming languages. The pure modules can be further classified into subgroups based on their tasks, which includes the following:
The impure modules of Nim code which depend on external libraries that are written in other programming languages such as C.

Libraries

A Nim program can use any library which can be used in a C and C++ program. Language bindings exist for many libraries, including GTK+, SDL2, Cairo, OpenGL, WinAPI, zlib, libzip, OpenSSL and cURL. Nim works with PostgreSQL, MySQL and SQLite databases. Nim can interface with the Lua and Python interpreters.

Examples

Hello world

The "Hello, World!" program in Nim:

echo
  1. Procedures can be called with no parentheses
echo "Hello, World!"

Another version of making a "Hello World" is...

stdout.write

Factorial

Program to calculate the factorial of a positive integer using the iterative approach:
import strutils
var n = 0
try:
stdout.write "Input positive integer number: "
n = stdin.readline.parseInt
except ValueError:
raise newException
var fact = 1
for i in 2..n:
fact = fact * i
echo fact
Using the module math from Nim's standard library:
import math
let i = fac
echo i

Reversing a string

A simple demonstration showing many of Nim's features.

proc reverse: string =
for i in countdown:
result.add s
let str1 = "Reverse This!"
echo "Reversed: ", reverse

One of the more exotic features is the implicit result variable. Every procedure in Nim with a non-void return type has an implicit result variable that represents the value that will be returned. In the for loop we see an invocation of countdown which is an iterator. If an iterator is omitted, the compiler will attempt to use an items iterator, if one is defined for the type specified.

Graphical user interface

Using GTK3 with gobject introspection through the module:
import gintro/
proc appActivate =
let window = newApplicationWindow
window.title = "GTK3 application with gobject introspection"
window.defaultSize =
showAll
proc main =
let app = newApplication
connect
discard run
main
This code requires the gintro module to work, which is not part of the standard library. To install the module gintro and many others you can use the tool nimble, which comes as part of nim. To install the gintro module with nimble you do the following:
nimble install gintro

Stropping

is a method to mark explicitly a letter sequence for a special purpose. Stropping is not used in most modern languages. Instead, keywords are reserved words and cannot be used as identifiers for variables or functions. Stropping allows the same letter sequence to be used both as a keyword and as an identifier, and simplifies parsing. For example, allowing a variable named if without clashing with the keyword if. In Nim, this is achieved via backticks, allowing any reserved word to be used as an identifier.

var `type`: int

Programming Paradigms

Object Oriented Programming (OOP)

Metaprogramming

Template

This is an example of metaprogramming in Nim using its template facilities.

template genType =
type
name = object
fieldname: fieldtype
genType
var x = Test
echo # 4566

The genType is invoked at compile-time and a Test type is created.

Generic

Generics may be used in procedures, templates and macros. They are defined after the proc's name in square brackets, as seen below.

proc addThese: T =
a + b
echo addThese # 3
echo addThese # 3

In addThese, T is the generic type, the compiler will accept any values for this function as long as both parameters and the return value are of the same type.
One can further clarify which types the procedure will accept by specifying a type class.
proc addTheseNumbers: T =
a + b
addTheseNumberswill then only work for types contained in the sum type.

Macros

Macros can literally rewrite parts of the code before it's compiled. Nim macros are powerful and can do many operations on the abstract syntax tree.
Here's a simple example, that creates a macro called twice:
import macros
macro twice: untyped =
result = quote do:
`arg`
`arg`
twice echo "Hello world!"

The twice macro in this example takes the echo statement in the form of an abstract syntax tree as input. In this example we decided to return this syntax tree without any manipulations applied to it. But we do it twice, hence the name of the macro. The end result is that the code gets rewritten by the macro to look like the following code at compile time:
echo "Hello world!"
echo "Hello world!"

Foreign Function Interface (FFI)

Nim's FFI is used to call functions written in the other programming languages that it can compile to. This means that libraries written in C, C++, Objective-C and JavaScript can be used in the Nim source code. One should be aware that both JavaScript and C, C++, or Objective-C libraries cannot be combined in the same program, as they are not as compatible with JavaScript as they are with each other. Both C++ and Objective-C are based on and compatible with C, but JavaScript is incompatible, as a dynamic, client-side web-based language.
The following program demonstrates the ease with which external C code can be used directly in Nim.

proc printf
printf

In this code the printf function is imported into Nim and then used.

Parallelism

To activate threading support in Nim, a program should be compiled with --threads:on command line argument. Each thread has a separate garbage collected heap and sharing of memory is restricted, which helps with efficiency and stops race conditions by the threads.
import locks
var
thr: array
L: Lock
proc threadFunc =
for i in interval.a..interval.b:
acquire # lock stdout
echo i
release
initLock
for i in 0..high:
createThread
joinThreads
Nim also has a channels module that simplifies passing data between threads.
import os
type
CalculationTask = object
id*: int
data*: int
CalculationResult = object
id*: int
result*: int
var task_queue: Channel
var result_queue: Channel
proc workerFunc =
result_queue.open
while true:
var task = task_queue.recv
result_queue.send
var workerThread: Thread
createThread
task_queue.open
task_queue.send
task_queue.send
while true:
echo "got result: ", repr)

Concurrency

Nim supports asynchronous IO via the asyncdispatch module, which adds async/await syntax via the macro system. An example of an asynchronous http server:
import asynchttpserver, asyncdispatch
var server = newAsyncHttpServer
proc cb =
await req.respond
waitFor server.serve

Experimental Features

Nim Community

The project has a bug tracker and wiki hosted by GitHub, and a forum. A presentation on Nim was given at the O'Reilly Open Source Convention in 2015. At FOSDEM 2020 four speakers represented Nim, with the creator of the language, Andreas Rumpf, being one of them.