Recent from talks
Nothing was collected or created yet.
Nim (programming language)
View on Wikipedia
| Nim | |
|---|---|
The Nim crown logo | |
| Paradigms | Multi-paradigm: compiled, concurrent, procedural, imperative, functional, object-oriented, meta |
| Designed by | Andreas Rumpf |
| Developer | Nim Lang Team[1] |
| First appeared | 2008 |
| Stable release | 2.2.6[2] |
| Typing discipline | Static,[3] strong,[4] inferred, structural |
| Scope | Lexical |
| Implementation language | Pascal (2005–2008) Nim (2008–present, self-hosted) |
| Platform | IA-32, x86-64, ARM, Aarch64, RISC-V, PowerPC ...[5] |
| OS | Cross-platform[6] |
| License | MIT License[7] |
| Filename extensions | .nim, .nims, .nimble |
| Website | nim-lang |
| Influenced by | |
| Ada, Modula-3, Lisp, C++, Object Pascal, Python, Oberon, Rust, ParaSail[8] | |
Nim is a general-purpose, multi-paradigm, statically typed, compiled, high-level system programming language.[9] It was designed and developed by a team led by Andreas Rumpf. Nim aims to be "efficient, expressive, and elegant",[10] and supports metaprogramming, functional, message passing,[11] procedural, and object-oriented programming paradigms. Nim includes features such as compile-time code generation, algebraic data types, and a foreign function interface (FFI) for interfacing with C, C++, Objective-C, and JavaScript. It also supports compilation to these same languages as intermediate representations.
Description
[edit]Nim is statically typed.[12] It supports compile-time metaprogramming features such as syntactic macros and term rewriting macros.[13] Term rewriting macros enable library implementations of common data structures, such as bignums and matrices, to be implemented efficiently and with syntactic integration, as if they were built-in language facilities.[14] Iterators are supported and can be used as first class entities,[13] 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 overloaded, and generics are further enhanced by Nim's support for type classes. Operator overloading is also supported.[13] Nim includes multiple tunable memory management strategies, including tracing garbage collection, reference counting, and fully manual systems, with the default being deterministic reference counting with optimizations via move semantics and cycle collection via trial deletion.[15]
[Nim] ... presents a most original design that straddles Pascal and Python and compiles to C code or JavaScript.[16]
— Andrew Binstock, editor-in-chief of Dr. Dobb's Journal, 2014
As of August 2023[update], Nim compiles to C, C++, JavaScript, Objective-C,[17] and LLVM.[18]
History
[edit]| Branch | Version | Release date[19] |
|---|---|---|
| 0.x | 0.10.2 | 2014-12-29 |
| 0.11.2 | 2015-05-04 | |
| 0.12.0 | 2015-10-27 | |
| 0.13.0 | 2016-01-18 | |
| 0.14.2 | 2016-06-09 | |
| 0.15.2 | 2016-10-23 | |
| 0.16.0 | 2017-01-08 | |
| 0.17.2 | 2017-09-07 | |
| 0.18.0 | 2018-03-01 | |
| 0.19.6 | 2019-05-13 | |
| 0.20.2 | 2019-06-17 | |
| 1.0 | 1.0.0 | 2019-09-23 |
| 1.0.10 | 2020-10-27 | |
| 1.2 | 1.2.0 | 2020-04-03 |
| 1.2.18 | 2022-02-09 | |
| 1.4 | 1.4.0 | 2020-10-16 |
| 1.4.8 | 2021-05-25 | |
| 1.6 | 1.6.0 | 2021-10-19 |
| 1.6.20 | 2024-04-16 | |
| 2.0 | 2.0.0 | 2023-08-01 |
| 2.0.16 | 2025-04-22 | |
| 2.2 | 2.2.0 | 2024-10-02 |
| 2.2.6 | 2025-10-31 | |
Legend: Unsupported Supported Latest version | ||
| For each 0.x branch, only the latest point release is listed. For later branches, the first and the latest point release is listed. | ||
Andreas Rumpf is the designer and original implementer of Nim. He received a diploma in computer science from the University of Kaiserslautern-Landau, Germany. His research interests include hard real-time systems, embedded systems, compiler construction and artificial intelligence.[20]
Nim's initial development was started in 2005 under the name Nimrod and was made public in 2008.[21]: 4–11
The first version of the Nim compiler was written in Pascal using the Free Pascal compiler.[22] In 2008, a version of the compiler written in Nim was released.[23] The compiler is free and open-source software, and is being developed by a community of volunteers working with Andreas Rumpf.[24] The language was officially renamed from Nimrod to Nim with the release of version 0.10.2 in December 2014.[25] On 23 September 2019, version 1.0 of Nim was released, signifying the maturing of the language and its toolchain. On 1 August 2023, version 2.0 of Nim was released, signifying the completion, stabilization of, and switch to the ARC/ORC memory model.[26]
Language design
[edit]Syntax
[edit]The syntax of Nim resembles that of Python.[27] Code blocks and nesting statements are identified through use of whitespace, according to the offside-rule. Many keywords are identical to their Python equivalents, which are mostly English keywords, whereas other programming languages usually use punctuation. With the goal of improving upon its influence languages, even though Nim supports indentation-based syntax like Python, it introduced additional flexibility. For example, a single statement may span multiple lines if a comma or binary operator is at the end of each line. Nim also supports user-defined operators.
Unlike Python, Nim implements (native) static typing. Nim's type system allows for easy type conversion, casting, and provides syntax for generic programming. Nim notably provides type classes which can stand in for multiple types, and provides several such type classes 'out of the box'. Type classes allow working with several types as if they were a single type. For example:
openarray– Represents arrays of different sizes, sequences, and stringsSomeSignedInt– Represents all the signed integer typesSomeInteger– Represents all the Integer types, signed or notSomeOrdinal– Represents all the basic countable and ordered types, except of non integer number
This code sample demonstrates the use of typeclasses in Nim:
# Let's declare a function that takes any type of number and displays its double
# In Nim functions with side effect are called "proc"
proc timesTwo(i: SomeNumber) =
echo i * 2
# Let's write another function that takes any ordinal type, and returns
# the double of the input in its original type, if it is a number;
# or returns the input itself otherwise.
# We use a generic Type(T), and precise that it can only be an Ordinal
func twiceIfIsNumber[T: SomeOrdinal](i: T): T =
when T is SomeNumber: # A `when` is an `if` evaluated during compile time
result = i * 2 # You can also write `return i * 2`
else:
# If the Ordinal is not a number it is converted to int,
# multiplied by two, and reconverted to its based type
result = (i.int * 2).T
echo twiceIfIsNumber(67) # Passes an int to the functionecho twiceIfIsNumber(67u8) # Passes an uint8echo twiceIfIsNumber(true) # Passes a bool (Which is also an Ordinal)
Influence
[edit]According to the language creator, Nim was conceived to combine the best parts of Ada typing system, Python flexibility, and powerful Lisp macro system.[28]
Nim was influenced by specific characteristics of existing languages, including the following:
- Modula-3: traced vs untraced pointers
- Object Pascal: type safe bit sets (set of char), case statement syntax, various type names and filenames in the standard library
- Ada: subrange types, distinct type, safe variants – case objects
- C++: operator overloading, generic programming
- Python: Off-side rule
- Lisp: Macro system, AST manipulation, homoiconicity
- Oberon: export marker
- C#: async/await, lambda macros
- ParaSail: pointer-free programming[8]
Uniform function call syntax
[edit]Nim supports uniform function call syntax (UFCS)[29] and identifier equality, which provides a large degree of flexibility in use.
For example, each of these lines print "hello world", just with different syntax:
echo "hello world"
echo("hello world")
"hello world".echo()
"hello world".echo
echo("hello", " world")
"hello".echo(" world")
"hello".echo " world"
Identifier equality
[edit]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. This is to enable a mixture of styles across libraries: one user can write a library using snake_case as a convention, and it can be used by a different user in a camelCase style without issue.[30]
const useHttps = true
assert useHttps == useHttps
assert useHTTPS == useHttps
assert use_https == useHttps
Stropping
[edit]The stropping feature allows the use of any name for variables or functions, even when the names are reserved words for keywords. An example of stropping is the ability to define a variable named if, without clashing with the keyword if. Nim's implementation of this is achieved via backticks, allowing any reserved word to be used as an identifier.[31]
type Type = object
`int`: int
let `object` = Type(`int`: 9)
assert `object` is Type
assert `object`.`int` == 9
var `var` = 42
let `let` = 8
assert `var` + `let` == 50
const `assert` = true
assert `assert`
Compiler
[edit]The Nim compiler emits fast, optimized C code by default. It defers compiling-to-object code to an external C compiler[32] to leverage existing compiler optimization and portability. Many C compilers are supported, including Clang, Microsoft Visual C++ (MSVC), MinGW, and GNU Compiler Collection (GCC). The Nim compiler can also emit C++, Objective-C, and JavaScript code to allow easy interfacing with application programming interfaces (APIs) written in those languages;[9] developers can simply write in Nim, then compile to any supported language. This also allows writing applications for iOS and Android. There is also an unofficial LLVM backend, allowing use of the Nim compiler in a stand-alone way.[18]
The Nim compiler is self-hosting, meaning it is written in the Nim language.[33] The compiler supports cross-compiling, so it is able to compile software for any of the supported operating systems, no matter the development machine. This is useful for compiling applications for embedded systems, and for uncommon and obscure computer architectures.[citation needed]
Compiler options
[edit]By default, the Nim compiler creates a debug build.[34]
With the option -d:release a release build can be created, which is optimized for speed and contains fewer runtime checks.[34]
With the option -d:danger all runtime checks can be disabled, if maximum speed is desired.[34]
Memory management
[edit]Nim supports multiple memory management strategies, including the following:[35]
--mm:arc– Automatic reference counting (ARC) with move semantics optimizations, offers a shared heap. It offers fully deterministic performance for hard realtime systems.[36] Reference cycles may cause memory leaks: these may be dealt with by manually annotating{.acyclic.}pragmas or by using--mm:orc.--mm:orc– Same as--mm:arcbut adds a cycle collector (the "O") based on "trial deletion".[37] The cycle collector only analyzes types if they are potentially cyclic.--mm:refc– Standard deferred reference counting based garbage collector with a simple mark-and-sweep backup GC in order to collect cycles. Heaps are thread-local.--mm:markAndSweep– Simple mark-and-sweep based garbage collector. Heaps are thread-local.--mm:boehm– Boehm based garbage collector, it offers a shared heap.--mm:go– Go's garbage collector, useful for interoperability with Go. Offers a shared heap.--mm:none– No memory management strategy nor a garbage collector. Allocated memory is simply never freed, unless manually freed by the developer's code.
As of Nim 2.0, ORC is the default GC.[26]
Development tools
[edit]Bundled
[edit]Many tools are bundled with the Nim install package, including:
Nimble
[edit]Nimble is the standard package manager used by Nim to package Nim modules.[38] It was initially developed by Dominik Picheta, who is also a core Nim developer. Nimble has been included as Nim's official package manager since 27 October 2015, the v0.12.0 release.[39]
Nimble packages are defined by .nimble files, which contain information about the package version, author, license, description, dependencies, and more.[21]: 132 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 JavaScript Object Notation (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 comes with the Nim compiler. Thus, it is possible to test the Nimble environment by running: nimble -v. This command will reveal the version number, compiling date and time, and Git hash of nimble. Nimble uses the Git package, which must be available for Nimble to function properly. The Nimble command-line is used as an interface for installing, removing (uninstalling), and upgrading–patching module packages.[21]: 130–131
c2nim
[edit]c2nim is a source-to-source compiler (transcompiler or transpiler) meant to be used on C/C++ headers to help generate new Nim bindings.[40] The output is human-readable Nim code that is meant to be edited by hand after the translation process.
koch
[edit]koch is a maintenance script that is used to build Nim, and provide HTML documentation.[41]
nimgrep
[edit]nimgrep is a generic tool for manipulating text. It is used to search for regex, peg patterns, and contents of directories, and it can be used to replace tasks. It is included to assist with searching Nim's style-insensitive identifiers.[42]
nimsuggest
[edit]nimsuggest is a tool that helps any source code editor query a .nim source file to obtain useful information like definition of symbols or suggestions for completions.[43]
niminst
[edit]niminst is a tool to generate an installer for a Nim program.[44] It creates .msi installers for Windows via Inno Setup, and install and uninstall scripts for Linux, macOS, and Berkeley Software Distribution (BSD).
nimpretty
[edit]nimpretty is a source code beautifier, used to format code according to the official Nim style guide.[45]
Testament
[edit]Testament is an advanced automatic unit tests runner for Nim tests. Used in developing Nim, it offers process isolation tests, generates statistics about test cases, supports multiple targets and simulated Dry-Runs, has logging, can generate HTML reports, can skip tests from a file, and more.
Other notable tools
[edit]Some notable tools not included in the Nim distribution include:
choosenim
[edit]choosenim was developed by Dominik Picheta, creator of the Nimble package manager, as a tool to enable installing and using multiple versions of the Nim compiler. It downloads any Nim stable or development compiler version from the command line, enabling easy switching between them.[46]
nimpy
[edit]nimpy is a library that enables convenient Python integration in Nim programs.[47]
pixie
[edit]pixie is a feature-rich 2D graphics library, similar to Cairo or the Skia. It uses SIMD acceleration to speed-up image manipulation drastically. It supports many image formats, blending, masking, blurring, and can be combined with the boxy library to do hardware accelerated rendering.
nimterop
[edit]nimterop is a tool focused on automating the creation of C/C++ wrappers needed for Nim's foreign function interface.[48]
Libraries
[edit]Pure/impure libraries
[edit]Pure libraries are modules written in Nim only. They include no wrappers to access libraries written in other programming languages.
Impure libraries are modules of Nim code which depend on external libraries that are written in other programming languages such as C.
Standard library
[edit]The Nim standard library includes modules for all basic tasks, including:[49]
- System and core modules
- Collections and algorithms
- String handling
- Time handling
- Generic Operating System Services
- Math libraries
- Internet Protocols and Support
- Threading
- Parsers
- Docutils
- XML Processing
- XML and HTML code generator
- Hashing
- Database support (PostgreSQL, MySQL and SQLite)
- Wrappers (Win32 API, POSIX)
Use of other libraries
[edit]A Nim program can use any library which can be used in a C, C++, or JavaScript program. Language bindings exist for many libraries, including GTK,[50][51] Qt QML,[52] wxWidgets,[53] SDL 2,[54][55] Raylib,[56] Godot,[57] UE5,[58] Cairo,[59] OpenGL,[60] Vulkan,[61] WinAPI,[62] zlib, libzip, OpenSSL and cURL.[63] Nim works with PostgreSQL, MySQL, and SQLite databases.
There are open source tools of various degree of support that can be used to interface Nim with Lua,[64] Julia,[65] Rust,[66] C#,[67] and Python[68] programming languages or transpile Nim to TypeScript.[69]
Examples
[edit]Hello world
[edit]The "Hello, World!" program in Nim:
echo("Hello, World!")
# Procedures can be called with no parentheses
echo "Hello, World!"
Another version of "Hello World" can be accomplished by calling the write function with the stdout stream:
stdout.write("Hello, World!\n")
write(stdout, "Hello, World!\n")
Fibonacci
[edit]Several implementations of the Fibonacci function, showcasing implicit returns, default parameters, iterators, recursion, and while loops:
proc fib(n: Natural): Natural =
if n < 2:
return n
else:
return fib(n-1) + fib(n-2)
func fib2(n: int, a = 0, b = 1): int =
if n == 0: a else: fib2(n-1, b, a+b)
iterator fib3: int =
var a = 0
var b = 1
while true:
yield a
swap a, b
b += a
Factorial
[edit]Program to calculate the factorial of a positive integer using the iterative approach, showcasing try/catch error handling and for loops:
import std/strutils
var n = 0
try:
stdout.write "Input positive integer number: "
n = stdin.readline.parseInt
except ValueError:
raise newException(ValueError, "You must enter a positive number")
var fact = 1
for i in 2..n:
fact = fact * i
echo fact
Using the module math from Nim's standard library:
import std/math
echo fac(x)
Reversing a string
[edit]A simple demonstration showing the implicit result variable and the use of iterators.
proc reverse(s: string): string =
for i in countdown(s.high, 0):
result.add s[i]
let str1 = "Reverse This!"
echo "Reversed: ", reverse(str1)
One of Nim's 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 to 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
[edit]Using GTK 3 with GObject introspection through the gintro module:
import gintro/[gtk, glib, gobject, gio]
proc appActivate(app: Application) =
let window = newApplicationWindow(app)
window.title = "GTK3 application with gobject introspection"
window.defaultSize = (400, 400)
showAll(window)
proc main =
let app = newApplication("org.gtk.example")
connect(app, "activate", appActivate)
discard run(app)
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
Programming paradigms
[edit]Functional programming
[edit]Functional programming is supported in Nim through first-class functions and code without side effects via the noSideEffect pragma or the func keyword.[70] Nim will perform side effect analysis and raise compiling errors for code that does not obey the contract of producing no side effects when compiled with the experimental feature strictFuncs, planned to become the default in later versions.[71]
Contrary to purely functional programming languages, Nim is a multi-paradigm programming language, so functional programming restrictions are opt-in on a function-by-function basis.
First-class functions
[edit]Nim supports first-class functions by allowing functions to be stored in variables or passed anonymously as parameters to be invoked by other functions.[72] The std/sugar module provides syntactic sugar for anonymous functions in type declarations and instantiation.
import std/[sequtils, sugar]
let powersOfTwo = @[1, 2, 4, 8, 16, 32, 64, 128, 256]
proc filter[T](s: openArray[T], pred: T -> bool): seq[T] =
result = newSeq[T]()
for i in 0 ..< s.len:
if pred(s[i]):
result.add(s[i])
echo powersOfTwo.filter(proc (x: int): bool = x > 32)
# syntactic sugar for the above, provided as a macro from std/sugar
echo powersOfTwo.filter(x => x > 32)
proc greaterThan32(x: int): bool = x > 32
echo powersOfTwo.filter(greaterThan32)
Side effects
[edit]Side effects of functions annotated with the noSideEffect pragma are checked, and the compiler will refuse to compile functions failing to meet those. Side effects in Nim include mutation, global state access or modification, asynchronous code, threaded code, and IO. Mutation of parameters may occur for functions taking parameters of var or ref type: this is expected to fail to compile with the currently-experimental strictFuncs in the future.[73] The func keyword introduces a shortcut for a noSideEffect pragma.[74]
func binarySearch[T](a: openArray[T]; elem: T): int# is short for...proc binarySearch[T](a: openArray[T]; elem: T): int{.noSideEffect.} {.experimental: "strictFuncs".}typeNode = ref objectle, ri: Nodedata: stringfunc len(n: Node): int =# valid: len does not have side effectsvar it = nwhile it != nil:inc resultit = it.rifunc mut(n: Node) =let m = n # is the statement that connected the mutation to the parameterm.data = "yeah" # the mutation is here# Error: 'mut' can have side effects# an object reachable from 'n' is potentially mutated
Function composition
[edit]Uniform function call syntax allows the chaining of arbitrary functions, perhaps best exemplified with the std/sequtils library.[75]
import std/[sequtils, sugar]
let numbers = @[1, 2, 3, 4, 5, 6, 7, 8, 7, 6, 5, 4, 3, 2, 1]
# a and b are special identifiers in the foldr macro
echo numbers.filter(x => x > 3).deduplicate.foldr(a + b) # 30
Algebraic data types and pattern matching
[edit]Nim has support for product types via the object type, and for sum types via object variants: raw representations of tagged unions, with an enumerated type tag that must be safely matched upon before fields of variants can be accessed.[76] These types can be composed algebraically. Structural pattern matching is available, but relegated to macros in various third-party libraries.[77]
import std/tables
type
Value = uint64
Ident = string
ExprKind = enum
Literal, Variable, Abstraction, Application
Expr = ref object
case kind: ExprKind
of Literal:
litIdent: Value
of Variable:
varIdent: Ident
of Abstraction:
paramAbs: Ident
funcAbs: Expr
of Application:
funcApp, argApp: Expr
func eval(expr: Expr, context: var Table[Ident, Value]): Value =
case expr.kind
of Literal:
return expr.litIdent
of Variable:
return context[expr.varIdent]
of Application:
case expr.funcApp.kind
of Abstraction:
context[expr.funcApp.paramAbs] = expr.argApp.eval(context)
return expr.funcAbs.eval(context)
else:
raise newException(ValueError, "Invalid expression!")
else:
raise newException(ValueError, "Invalid expression!")
Object-oriented programming
[edit]Despite being primarily an imperative and functional language, Nim supports various features for enabling object-oriented paradigms.[78][79]
Subtyping and inheritance
[edit]Nim supports limited inheritance by use of ref objects and the of keyword.[79] To enable inheritance, any initial ("root") object must inherit from RootObj. Inheritance is of limited use within idiomatic Nim code: with the notable exception of Exceptions.[80]
type Animal = ref object of RootObj
name: string
age: int
type Dog = ref object of Animal
type Cat = ref object of Animal
var animals: seq[Animal] = @[]
animals.add(Dog(name: "Sparky", age: 10))
animals.add(Cat(name: "Mitten", age: 10))
for a in animals:
assert a of Animal
Subtyping relations can also be queried with the of keyword.[79]
Method calls and encapsulation
[edit]Nim's uniform function call syntax enables calling ordinary functions with syntax similar to method call invocations in other programming languages. This is functional for "getters": and Nim also provides syntax for the creation of such "setters" as well. Objects may be made public on a per-field basis, providing for encapsulation.
type Socket* = ref object
host: int # private, lacks export marker
# getter of host address
proc host*(s: Socket): int = s.host
# setter of host address
proc `host=`*(s: var Socket, value: int) =
s.host = value
var s: Socket
new s
assert s.host == 0 # same as host(s), s.host()
s.host = 34 # same as `host=`(s, 34)
Dynamic dispatch
[edit]Static dispatch is preferred, more performant, and standard even among method-looking routines.[79] Nonetheless, if dynamic dispatch is so desired, Nim provides the method keyword for enabling dynamic dispatch on reference types.
import std/strformat
type
Person = ref object of RootObj
name: string
Student = ref object of Person
Teacher = ref object of Person
method introduce(a: Person) =
raise newException(CatchableError, "Method without implementation override")
method introduce(a: Student) =
echo &"I am a student named {a.name}!"
method introduce(a: Teacher) =
echo &"I am a teacher named {a.name}!"
let people: seq[Person] = @[Teacher(name: "Alice"), Student(name: "Bob")]
for person in people:
person.introduce()
Metaprogramming
[edit]Templates
[edit]Nim supports simple substitution on the abstract syntax tree via its templates.
template genType(name, fieldname: untyped, fieldtype: typedesc) =
type
name = object
fieldname: fieldtype
genType(Test, foo, int)
var x = Test(foo: 4566)
echo(x.foo) # 4566
The genType is invoked at compile-time and a Test type is created.
Generics
[edit]Nim supports both constrained and unconstrained generic programming. Generics may be used in procedures, templates and macros. Unconstrained generic identifiers (T in this example) are defined after the routine's name in square brackets. Constrained generics can be placed on generic identifiers, or directly on parameters.
proc addThese[T](a, b: T): T = a + b
echo addThese(1, 2) # 3 (of int type)
echo addThese(uint8 1, uint8 2) # 3 (of uint8 type)
# we don't want to risk subtracting unsigned numbers!
proc subtractThese[T: SomeSignedInt | float](a, b: T): T = a - b
echo subtractThese(1, 2) # -1 (of int type)
import std/sequtils
# constrained generics can also be directly on the parameters
proc compareThese[T](a, b: string | seq[T]): bool =
for (i, j) in zip(a, b):
if i != j:
return false
One can further clarify which types the procedure will accept by specifying a type class (in the example above, SomeSignedInt).[81]
Macros
[edit]Macros can rewrite parts of the code at compile-time. Nim macros are powerful and can operate on the abstract syntax tree before or after semantic checking.[82]
Here's a simple example that creates a macro to call code twice:
import std/macros
macro twice(arg: untyped): 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 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)
[edit]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.[21]: 226
The following program shows the ease with which external C code can be used directly in Nim.
proc printf(formatstr: cstring) {.header: "<stdio.h>", varargs.}
printf("%s %d\n", "foo", 5)
In this code the printf function is imported into Nim and then used.
Basic example using 'console.log' directly for the JavaScript compiling target:
proc log(args: any) {.importjs: "console.log(@)", varargs.}
log(42, "z", true, 3.14)
The JavaScript code produced by the Nim compiler can be executed with Node.js or a web browser.
Parallelism
[edit]This section needs expansion. You can help by adding missing information. (June 2019) |
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 std/locks
var
thr: array[0..4, Thread[tuple[a,b: int]]]
L: Lock
proc threadFunc(interval: tuple[a,b: int]) {.thread.} =
for i in interval.a..interval.b:
acquire(L) # lock stdout
echo i
release(L)
initLock(L)
for i in 0..high(thr):
createThread(thr[i], threadFunc, (i*10, i*10+5))
joinThreads(thr)
Nim also has a channels module that simplifies passing data between threads.
import std/os
type
CalculationTask = object
id*: int
data*: int
CalculationResult = object
id*: int
result*: int
var task_queue: Channel[CalculationTask]
var result_queue: Channel[CalculationResult]
proc workerFunc() {.thread.} =
result_queue.open()
while true:
var task = task_queue.recv()
result_queue.send(CalculationResult(id: task.id, result: task.data * 2))
var workerThread: Thread[void]
createThread(workerThread, workerFunc)
task_queue.open()
task_queue.send(CalculationTask(id: 1, data: 13))
task_queue.send(CalculationTask(id: 2, data: 37))
while true:
echo "got result: ", repr(result_queue.recv())
Concurrency
[edit]This section needs expansion. You can help by adding missing information. (June 2019) |
Asynchronous IO is supported either via the asyncdispatch module in the standard library or the external chronos library.[83] Both libraries add async/await syntax via the macro system, without need for special language support. An example of an asynchronous HTTP server:
import std/[asynchttpserver, asyncdispatch]
# chronos could also be alternatively used in place of asyncdispatch,
# with no other changes.
var server = newAsyncHttpServer()
proc cb(req: Request) {.async.} =
await req.respond(Http200, "Hello World")
waitFor server.serve(Port(8080), cb)
Community
[edit]Online
[edit]Nim has an active community on the self-hosted, self-developed official forum.[84] Further, the project uses a Git repository, bug tracker, RFC tracker, and wiki hosted by GitHub, where the community engages with the language.[85] There are also official online chat rooms, bridged between IRC, Matrix, Discord, Gitter, and Telegram.[86]
Conventions
[edit]The first Nim conference, NimConf, took place on 20 June 2020. It was held digitally due to COVID-19, with an open call for contributor talks in the form of YouTube videos.[87] The conference began with language overviews by Nim developers Andreas Rumpf and Dominik Picheta. Presentation topics included talks about web frameworks, mobile development, Internet of things (IoT) devices, and game development, including a talk about writing Nim for Game Boy Advance.[88] NimConf 2020 is available as a YouTube playlist.[89] NimConf 2021 occurred the following year, was also held digitally, and included talks about game development, REPLs, real-time operating systems, Nim in the industry, object–relational mapping (ORM), fuzzing, language design, and graphics libraries.[90]
In addition to official conferences, Nim has been featured at various other conventions. A presentation on Nim was given at the O'Reilly Open Source Convention (OSCON) in 2015.[91][92][93] Four speakers represented Nim at FOSDEM 2020, including the creator of the language, Andreas Rumpf.[94] At FOSDEM 2022, Nim hosted their own developer room virtually due to the COVID-19 pandemic.[95] Talks were held on concurrency, embedded programming, programming for GPUs, entity-component systems, game development, rules engines, Python interop, and metaprogramming.[96]
See also
[edit]References
[edit]- ^ "Contributors to nim-lang/Nim". GitHub. Retrieved 2022-03-23.
- ^ https://github.com/nim-lang/Nim/releases/tag/v2.2.6.
{{cite web}}: Missing or empty|title=(help) - ^ "Nim by example". GitHub. Retrieved 2014-07-20.
- ^ Караджов, Захари; Станимиров, Борислав (2014). Метапрограмиране с Nimrod. VarnaConf (in Bulgarian). Retrieved 2014-07-27.
- ^ "Packaging Nim". Retrieved 2022-03-23.
- ^ "Install Nim". Retrieved 2018-10-12.
- ^ "copying.txt". GitHub.
- ^ a b Rumpf, Andreas (2017-10-19). "Nim without GC". Araq's Musings. Retrieved 2020-09-01.
- ^ a b Rumpf, Andreas (2014-02-11). "Nimrod: A new systems programming language". Dr. Dobb's Journal. Retrieved 2014-07-20.
- ^ "The Nim Programming Language". Nim-lang.org. Retrieved 2014-07-20.
- ^ "FAQ". nim-lang.org. Retrieved 2015-03-27.
- ^ Kehrer, Aaron (akehrer) (2015-01-05). "Nim Syntax". GitHub. Retrieved 2015-01-05.
- ^ a b c "Nim Manual". Nim-lang.org. Retrieved 2014-07-20.
- ^ "Strangeloop Nim presentation". Archived from the original on 2014-07-13. Retrieved 2015-04-30.
- ^ "Nim's Memory Management". nim-lang.org. Retrieved 2023-08-17.
- ^ Binstock, Andrew (2014-01-07). "The Rise And Fall of Languages in 2013". Dr. Dobb's Journal. Retrieved 2018-10-08.
- ^ Nim Compiler User Guide
- ^ a b Sieka, Jacek (2020-07-18), arnetheduck/nlvm, retrieved 2020-07-21
- ^ "Nim Releases". Nim Project. Retrieved 2020-01-26.
- ^ Andreas Rumpf. Mastering Nim: A complete guide to the programming language.
- ^ a b c d Picheta, Dominik (2017). Nim in Action. Manning Publications. ISBN 978-1617293436.
- ^ "Nim Pascal Sources". GitHub. Retrieved 2013-04-05.
- ^ "News". Nim-lang.org. Archived from the original on 2016-06-26. Retrieved 2016-06-11.
- ^ "Contributors". GitHub. Retrieved 2013-04-05.
- ^ Picheta, Dominik (2014-12-29). "Version 0.10.2 released". Nim-lang.org. Retrieved 2018-10-17.
- ^ a b "Nim v2.0 released". Nim Programming Language. Retrieved 2023-08-17.
- ^ Yegulalp, Serdar (2017-01-16). "Nim language draws from best of Python, Rust, Go, and Lisp". InfoWorld.
- ^ Interview with Nim language creator Andreas Rumpf, 2020-03-09, retrieved 2023-10-15
- ^ "Nim Manual: Method call syntax". Retrieved 2018-10-12.
- ^ "Nim Manual: Identifier Equality". nim-lang.org. Retrieved 2023-08-17.
- ^ Picheta, Dominik (dom96); Wetherfordshire, Billingsly (fowlmouth); Felsing, Dennis (def-); Raaf, Hans (oderwat); Dunn, Christopher (cdunn2001); wizzardx (2017-10-25). "Tips and tricks". GitHub. Retrieved 2018-10-17.
{{cite web}}: CS1 maint: numeric names: authors list (link) - ^ Rumpf, Andreas (2014-01-15). Nimrod: A New Approach to Metaprogramming. InfoQ. Event occurs at 2:23. Retrieved 2014-07-20.
- ^ Rumpf, Andreas (2018-10-12). "Nim Compiling". GitHub. Retrieved 2018-10-17.
- ^ a b c "Nim Compiler User Guide".
- ^ "Nim's Memory Management". nim-lang.org. Retrieved 2024-07-28.
- ^ "Introduction to ARC/ORC in Nim". Nim Programming Language. Retrieved 2023-08-17.
- ^ "ORC - Vorsprung durch Algorithmen". Nim Programming Language. Retrieved 2023-08-17.
- ^ "Nimble". GitHub. Retrieved 2018-10-12.
- ^ "Nim v0.12.0 release". GitHub. Retrieved 2020-11-28.
- ^ "c2nim". GitHub. Retrieved 2018-10-12.
- ^ "Nim maintenance script". nim-lang.org. Retrieved 2021-11-16.
- ^ "nimgrep User's manual". nim-lang.org. Retrieved 2021-11-16.
- ^ "Nim IDE Integration Guide". nim-lang.org. Retrieved 2021-11-16.
- ^ "niminst User's manual". nim-lang.org. Retrieved 2021-11-16.
- ^ "Tools available with Nim". nim-lang.org. 2021-10-19. Archived from the original on 2015-05-09. Retrieved 2022-02-18.
- ^ "choosenim". GitHub. Retrieved 2018-10-12.
- ^ Glukhov, Yuriy (2021-11-12), nimpy, retrieved 2021-11-16
- ^ nimterop/nimterop, nimterop, 2021-11-12, retrieved 2021-11-16
- ^ Nim Standard Library
- ^ Installation, The Nim programming language, 2021-09-25, retrieved 2021-11-16
- ^ StefanSalewski (2021-11-15), High level GTK4 and GTK3 bindings for the Nim programming language, retrieved 2021-11-16
- ^ "NimQml". GitHub. 2022-11-10.
- ^ "WxNim". GitHub. 2022-11-29.
- ^ SDL2 for Nim, The Nim programming language, 2021-10-26, retrieved 2021-11-16
- ^ Arabadzhi, Vladimir (2021-11-15), sdl2_nim 2.0.14.2, retrieved 2021-11-16
- ^ "naylib". GitHub. 2024-07-28.
- ^ "godot-nim". GitHub. 2024-07-28.
- ^ "NimForUE". GitHub. 2024-07-28.
- ^ Cairo, The Nim programming language, 2021-10-05, retrieved 2021-11-16
- ^ opengl, The Nim programming language, 2021-11-14, retrieved 2021-11-16
- ^ "vulkan". GitHub. 2024-07-28.
- ^ Ward (2021-11-15), Winim, retrieved 2021-11-16
- ^ "Nim Standard Library". Nim documentation. Archived from the original on 2015-04-06. Retrieved 2015-04-04.
- ^ Lim, Andri (jangko) (2018-10-17). "nimLUA". GitHub. Retrieved 2018-10-17.
- ^ "NimJL". GitHub. 2022-08-24.
- ^ "Nbindgen". GitHub. 2022-11-17.
- ^ "cs2nim". GitHub. 2022-10-10.
- ^ Glukhov, Yuriy (2020-07-20), yglukhov/nimpy, retrieved 2020-07-21
- ^ "ts2nim". GitHub. 2022-11-21.
- ^ "Nim Manual". nim-lang.org. Retrieved 2021-07-10.
- ^ "Nim Forum: Update on strict funcs". forum.nim-lang.org. Retrieved 2023-08-17.
- ^ "Nim by Example - First Class Functions".
- ^ "Nim Experimental Features: Strict Funcs".
- ^ "Nim Manual: Func".
- ^ "std/sequtils". nim-lang.org. Retrieved 2023-08-17.
- ^ "Nim Manual: Object variants". nim-lang.org. Retrieved 2023-08-17.
- ^ "src/fusion/matching". nim-lang.github.io. Retrieved 2023-08-17.
- ^ "Nim Tutorial (Part II): Object Oriented Programming". nim-lang.org. Retrieved 2023-08-17.
- ^ a b c d "Nim by Example - Object Oriented Programming". nim-by-example.github.io. Retrieved 2023-08-17.
- ^ "system/exceptions". nim-lang.org. Retrieved 2023-08-17.
- ^ "Nim Manual: Type Classes". nim-lang.org. Retrieved 2020-07-21.
- ^ "Nim Tutorial (Part III)". nim-lang.org. Retrieved 2023-08-17.
- ^ Chronos - An efficient library for asynchronous programming, Status, 2023-08-14, retrieved 2023-08-17
- ^ "Nim Forum". nim-lang.org. Retrieved 2015-05-04.
- ^ "Primary source code repository and bug tracker". GitHub. Retrieved 2015-05-04.
- ^ "Community". Nim Programming Language. Retrieved 2023-08-17.
- ^ "Nim Online Conference 2020". Nim. Retrieved 2020-11-28.
- ^ "NimConf 2020". Nim. Retrieved 2023-08-17.
- ^ "NimConf 2020 Playlist". YouTube. Retrieved 2020-11-28.
- ^ "NimConf 2021". NimConf 2021. Retrieved 2023-08-17.
- ^ "Nim at OSCON 2015". O'Reilly Open Source Convention (OSCON). O'Reilly Media. 2015-07-20. Archived from the original on 2015-10-06. Retrieved 2018-10-17.
- ^ Rumpf, Andreas; Swartz, Jason; Harrison, Matt. "Essential Languages: Nim, Scala, Python". O’Reilly. O'Reilly Media. Retrieved 2018-10-17.
- ^ Rumpf, Andreas (2015-10-26). OSCON 2015 – Nim: An Overview. YouTube (Video). Retrieved 2018-10-12.
- ^ "Events". fosdem.org. Retrieved 2020-02-17.
- ^ "Nim Devroom at FOSDEM 2022 - Call for Participation". Nim Programming Language. Retrieved 2023-08-17.
- ^ "Nim Programming Language devroom". archive.fosdem.org. Retrieved 2023-08-17.
External links
[edit]- Official website

- Nim on GitHub
- Information about Nim on Stack Overflow
- Computer Programming with the Nim Programming Language – A gentle Introduction by Stefan Salewski
Nim (programming language)
View on GrokipediaIntroduction
Overview
Nim is a general-purpose, multi-paradigm, statically typed, compiled systems programming language designed for efficiency and expressiveness. It compiles to the intermediate languages C, C++, JavaScript, or Objective-C, enabling seamless integration with existing ecosystems while producing highly optimized native code via these backends, as well as JavaScript code for web applications.[1][5] Developed with a focus on elegance and developer productivity, Nim emphasizes clean syntax and powerful metaprogramming capabilities to minimize boilerplate and enhance code readability. By default, Nim employs ORC (Optimized Reference Counting) for automatic memory management, which provides deterministic cleanup through reference counting.[6] ORC extends ARC (Automatic Reference Counting), a compile-time reference counting system that ensures deterministic memory management without runtime cycle collection, making it suitable for real-time applications.[7] Unlike traditional conservative garbage collection, which is still available as an option, ORC includes adaptive cycle detection to handle cyclic data structures while maintaining much of ARC's determinism.[6][8] Nim also supports manual memory allocation and destruction for performance-critical applications, allowing developers to choose the approach that best fits their needs. The language supports multiple programming paradigms, including procedural, object-oriented, and functional styles, providing flexibility for diverse software development tasks. Nim's primary use cases span systems programming, where its low-level control rivals C; web development through JavaScript backends; embedded systems via cross-compilation targets; and scripting for rapid prototyping. As of November 2025, the current stable version is Nim 2.2.6, released on October 31, 2025.[9]Design goals
Andreas Rumpf conceived Nim with the ambition to create a systems programming language that merges the readability and simplicity reminiscent of Python with the raw performance of C, enabling developers to write high-level code that compiles to efficient native binaries without runtime dependencies.[10] This vision prioritizes developer productivity alongside low-level control, addressing the trade-offs often seen in languages that favor either ease of use or speed.[1] The core design goals of Nim, as articulated by its creators, revolve around three pillars: efficiency, expressiveness, and elegance, listed in order of priority. Efficiency is achieved through compilation to optimized C, C++, or JavaScript code, resulting in minimal runtime overhead and support for deterministic memory management with features like destructors and move semantics, allowing performance comparable to hand-optimized C while avoiding garbage collection pauses in critical paths.[1] Expressiveness stems from powerful metaprogramming capabilities, including a macro system for abstract syntax tree manipulation and compile-time evaluation, which enable concise yet flexible abstractions without sacrificing type safety.[11] Elegance manifests in a clean, indentation-based syntax inspired by Python, Ada, and Modula-3, which minimizes verbosity typically associated with static typing while maintaining clarity and reducing boilerplate.[1] To broaden its appeal, Nim supports multiple programming paradigms, including imperative, procedural, object-oriented, and functional styles through generics and higher-order programming, allowing programmers from diverse backgrounds to adopt it without friction.[1] By compiling to optimized C, C++, Objective-C, or JavaScript code, Nim ensures high speed and portability across major platforms like Windows, Linux, macOS, and embedded systems, without compromising the productivity gains from expressive high-level features.[1] This balanced approach avoids the inefficiencies of purely dynamic languages and the cumbersome syntax of many static ones, positioning Nim as a versatile tool for systems, web, and scientific computing.[10]History
Origins and development
Nim was conceived by Andreas Rumpf in 2008 as a personal hobby project aimed at creating an efficient systems programming language.[12] Initially named Nimrod, the project was publicly released that year, with the first compiler implementation written in the language itself.[13] From the outset, Nimrod was designed as an open-source endeavor under the permissive MIT license, encouraging community contributions while maintaining Rumpf as the primary architect.[14] The language drew significant inspiration from established paradigms, particularly the modular structure and efficiency of Oberon in the Wirthian family, as well as Lisp's metaprogramming capabilities, blending them with influences from Python for readability and Ada for robustness.[14] Early development focused on core systems programming features, such as static typing and compilation to C, to achieve high performance without sacrificing expressiveness.[12] Key milestones included the release of version 0.8 in 2011, which introduced substantial improvements in syntax and compiler stability, solidifying its foundation.[15] In response to the negative slang connotation of "Nimrod" as a term for an idiot in American English, stemming from its sarcastic use in Looney Tunes cartoons such as those featuring Bugs Bunny, the language was renamed Nim in December 2014 as part of version 0.10.2.[16][17] This period saw increasing involvement from a growing team of contributors, transitioning from Rumpf's solo effort to a collaborative open-source project hosted on GitHub.[18] The culmination of these foundational efforts arrived with the stable version 1.0 release in September 2019, establishing Nim as a mature language ready for production use.[19]Major releases and updates
Nim 1.0 was released on September 23, 2019, establishing the core stability of the language after extensive development and community feedback, with no breaking changes to the syntax or semantics introduced in this milestone version.[19] Nim 2.0 arrived on August 1, 2023, as an evolutionary update that made the ORC (Optimized Reference Counting) memory management the default, providing deterministic memory handling without the pauses associated with traditional garbage collection. This release also introduced key improvements in error handling, including experimental definite assignment analysis via thestrictDefs pragma to enforce explicit variable initialization, always-enabled strict effects for better callback parameter tracking, and enhanced error messages with detailed type information. Refinements to the ARC/ORC models added hooks like =wasMoved and =dup for more efficient object management, alongside features such as nested tuple unpacking and top-down type inference.[20]
The Nim 2.2 series commenced with version 2.2.0 on October 2, 2024, incorporating nearly 1,000 commits focused on ORC stability, bug fixes for generics and static types, and enhancements to concurrency support through better integration with structured approaches and external libraries. This version improved the JavaScript backend with lambda lifting for closures and iterators, aiding asynchronous code generation, while also advancing C++ interoperability with features like custom constructors. Patch releases followed: 2.2.2 on February 5, 2025, addressing initial stability issues;[21] 2.2.4 on April 22, 2025, with over 100 bug fixes; and 2.2.6 on October 31, 2025, delivering further refinements for enterprise reliability.[22][23][24]
Ongoing development follows a roadmap emphasizing the evolution of the concurrency model, including the adoption of the Nim Intermediate Representation (NIR) to enable optimizations for multi-threading and async patterns, with a planned transition to formats like NIF for frontend-backend communication by late 2025. Community-driven enhancements continue to prioritize the JavaScript backend for web concurrency and overall ecosystem stability. In parallel, older features such as the original reference-counting garbage collector have been deprecated in favor of deterministic ARC/ORC options, which became the default in 2.0 to support real-time and performance-critical applications.[25][20]
Language design
Syntax and semantics
Nim employs an indentation-based syntax that relies on significant whitespace to delineate code blocks and nesting levels, akin to Python's approach for enhanced readability.[26] This means that statements within control structures like conditionals or loops are grouped by consistent indentation levels, typically using spaces rather than tabs, with the lexer tracking indentation via a stack to enforce structural rules.[26] The language's lexis defines identifiers as case-sensitive sequences beginning with a letter or underscore, followed by letters, digits, or underscores, while supporting Unicode characters with ordinal values greater than 127.[26] Keywords, such asif, while, and for, are case-insensitive, allowing variants like If or FOR to function equivalently, but identifiers remain case-sensitive to distinguish user-defined names.[26] To use a keyword as an identifier, Nim supports stropping by enclosing it in backticks, as in let `if` = true.[26]
Function calls in Nim feature a uniform syntax that treats method invocations flexibly, permitting both object-oriented notation like obj.method(arg) and procedural style like method(obj, arg).[27] For instance, the length of a string can be obtained via "abc".len or len("abc"), with the compiler resolving the call based on context and type.[27]
Semantically, Nim is a statically typed language that employs type inference to deduce types from context, reducing explicit annotations while ensuring compile-time type safety.[28] Expressions evaluate to values or l-values (locations that can be assigned to), such as arithmetic operations or conditional expressions like if x > 0: 1 else: 0, which produce a result without side effects unless specified.[29] Statements, in contrast, perform actions like declarations or control flow without yielding values, though statement lists can be wrapped in expressions for use in larger contexts.[29]
Control flow constructs follow declarative syntax with colon-separated bodies indented thereafter.[30] The if statement supports conditional execution with optional elif and else branches, as in:
if condition:
# indented statements
elif otherCondition:
# more statements
else:
# final statements
if condition:
# indented statements
elif otherCondition:
# more statements
else:
# final statements
while loop repeats a block until its boolean expression evaluates to false, e.g., while x > 0: x -= 1.[30] The for loop iterates over enumerable expressions, binding identifiers to successive elements, such as for i in 1..5: echo i.[30]
Nim allows operator overloading through procedure definitions with special names, enabling user-defined behavior for symbols like + or custom ones, provided they adhere to the language's operator grammar.[31] Operator precedence is stratified across 11 levels, from highest ($ for stringification and ^ for exponentiation) to lowest (logical not), with most operators left-associative and ^-prefixed ones right-associative; parentheses can override this for clarity.[31]
Type system
Nim employs a static type system where types are resolved and checked at compile time, ensuring type safety and enabling optimizations. The system is primarily structural, meaning type compatibility is determined by the internal structure of types rather than their names, except for specific cases like objects, enumerations, and distinct types which use nominal equivalence.[32] Strong type inference allows the compiler to deduce types from context, such as initializers in variable declarations or return expressions in procedures, minimizing the need for explicit type annotations while maintaining precision.[33] Built-in types in Nim include ordinal types like integers (e.g.,int, the platform-dependent natural-sized signed integer (typically 64 bits on 64-bit platforms), uint for the corresponding unsigned integer, and sized variants from 8 to 64 bits), booleans (bool), characters (char), and enumerations which define ordered sets of identifiers. Floating-point types consist of float (alias for float64), float32, and float64, adhering to IEEE 754 standards with built-in overflow and underflow detection. Other primitives are strings (string, a mutable sequence of characters with length prefixing), C-compatible strings (cstring, a null-terminated pointer), sequences (seq[T], resizable arrays), and tuples (tuple, heterogeneous fixed-size collections).[28][34][35]
Composite types extend these primitives for more complex data modeling. Objects (object) define structured records with fields, supporting optional inheritance from a root object for subtyping relations. Enumerations provide named constants with underlying ordinal values, useful for state representation. Distinct types, declared via distinct, wrap an existing type to create a semantically distinct but structurally related type, preventing implicit conversions for enhanced safety—such as Dollar = distinct int to model currency separately from general integers.[28][36][37]
Union types enable a value to hold one of several alternative types, declared using the | operator (e.g., int | float for numeric alternatives), facilitating flexible data representation without runtime overhead in simple cases. For discriminated unions, case objects (also known as variants) use a case statement within an object definition, with a discriminator field (typically an enum) selecting active branches—such as case kind: NodeKind; of nkInt: intVal: int; of nkStr: strVal: string—ensuring type-safe access while inactive fields remain inaccessible at compile time.[28][38]
Type compatibility emphasizes structural equivalence: two types are equal if their components match recursively, allowing interchangeable use of structurally identical types like tuples or arrays. Objects lack nominal subtyping by default, relying instead on explicit inheritance for subtype polymorphism, where a type A is a subtype of B if A inherits from B directly or indirectly. Convertible relations support implicit widening (e.g., int8 to int) and explicit casts, with distinct types requiring deliberate conversion to their base.[32][39]
Error handling integrates with the type system through exceptions, which are objects inheriting from Exception or Defect (for uncatchable errors like overflows), raised at runtime for conditions such as index out-of-bounds (IndexDefect) or arithmetic overflows (OverflowDefect). Additionally, result types like Result[T, E]—a common idiom often implemented as a discriminated union or tuple—encapsulate success values of type T alongside potential errors E, promoting functional-style error propagation without exceptions.[40][41][42]
Metaprogramming features
Nim's metaprogramming capabilities enable developers to generate and manipulate code at compile-time, facilitating powerful abstractions and code reuse without runtime overhead. These features, including generics, templates, macros, and concepts, allow the language to be extended dynamically while maintaining static typing and efficiency. By operating on the abstract syntax tree (AST) or through parameterization, they support the creation of domain-specific languages and optimized code generation, distinguishing Nim from languages with limited compile-time introspection.[3] Generics in Nim provide parameterized types and procedures, enabling type-safe polymorphism and reusable code across different types. They are defined using square brackets for type parameters, such asproc add[T](a, b: T): T, where T is resolved at compile-time during overload resolution. This mechanism ensures that the generated code is specialized for each type, avoiding boxing or dynamic dispatch, and supports advanced features like aliasing type parameters for efficiency. For instance, a generic sequence type like seq[T] can handle any element type while preserving performance comparable to native arrays.[3][43]
Templates offer a simple, unhygienic form of code generation through textual substitution at compile-time, ideal for boilerplate reduction and basic metaprogramming. Declared with the template keyword, they use untyped parameters to delay type checking until expansion, as in template additive(typ: typedesc) = proc +*(x, y: typ): typ {.borrow.}. This expands to define operator overloads for custom types, borrowing implementations from built-in types. Templates are particularly useful in the standard library for features like asynchronous programming, where they generate efficient state machines without runtime costs. Unlike more complex tools, templates prioritize simplicity over full AST control, making them suitable for straightforward reuse.[3][43]
Macros extend metaprogramming by allowing hygienic manipulation of the AST, enabling sophisticated code transformations during compilation. Defined with the macro keyword, they take typed or untyped parameters and return modified AST nodes, such as generating an enum from a string literal:
import macros, strutils
macro toEnum(words: static[string]): untyped =
result = newTree(nnkEnumTy, newEmptyNode())
for w in splitWhitespace(words):
result.add ident(w)
type
Color = toEnum"Red Green Blue Indigo"
import macros, strutils
macro toEnum(words: static[string]): untyped =
result = newTree(nnkEnumTy, newEmptyNode())
for w in splitWhitespace(words):
result.add ident(w)
type
Color = toEnum"Red Green Blue Indigo"
type Color = enum Red, Green, Blue, Indigo, demonstrating runtime-like introspection at compile-time. Macros are type-aware and support reflection via nodes like ident or newTree, but require careful handling to avoid infinite recursion or hygiene issues. They power advanced libraries by creating custom syntax while ensuring the final code compiles to efficient C.[3][43]
Concepts introduce compile-time type classes to constrain generics, ensuring that parameterized code only applies to types meeting specific requirements. Declared with the concept keyword, they specify operations or properties, e.g., concept Comparable = concept var t: Self; proc <(a, b: Self): bool. This can then be used in generics like proc sort[T: Comparable](x: seq[T]), enabling compile-time checks for compatibility and better error messages. Concepts facilitate duck typing within a static framework, improving code safety and expressiveness without runtime penalties, and integrate seamlessly with overload resolution for precise matching.[3]
Compile-time evaluation and reflection further enhance metaprogramming by executing expressions during compilation and inspecting code structure. Using static blocks or parameters, such as static: echo "Computed at compile-time", Nim evaluates constants or generates values like Fibonacci sequences in const fib = static(nextFib()). Reflection occurs primarily through macros accessing AST elements via typeof or node inspection, allowing dynamic code analysis. These features are restricted—no foreign function interfaces, closures, or reference types—to ensure safety, and they interleave with semantic analysis for verified results. Unlike runtime reflection in languages like Python, all operations resolve fully before transpilation to C, yielding zero-cost abstractions.[3]
In contrast to runtime features like dynamic typing or virtual methods, Nim's metaprogramming occurs entirely at compile-time, producing specialized, efficient machine code without indirection or interpretation overhead. This design ensures that abstractions like generics or macros vanish in the final binary, aligning with Nim's goals of performance and elegance.[3][43]
Programming paradigms
Imperative and procedural
Nim supports imperative programming through its core syntax for mutable state, control flow, and procedural abstractions, enabling developers to write straightforward, step-by-step code similar to languages like C or Pascal.[44] Procedures, known as "procs," serve as the primary building blocks for organizing code into reusable functions, emphasizing explicit control over execution and data modification.[45] Procedures are declared using theproc keyword, followed by the procedure name, a parameter list in parentheses, an optional return type after a colon, and the body. For example, a simple addition procedure is written as proc add(a, b: int): int = a + b, where a and b are parameters typed as integers, and the return type is int.[45] Parameters can include defaults, such as proc greet(name: string = "World"): string = "Hello, " & name, and support var for pass-by-reference modification, like proc increment(x: var int) = x += 1.[45] Return values are assigned via an implicit result variable or the return statement, with the compiler ensuring type safety.[45]
Mutability is managed explicitly through var for variables that can be reassigned and let for constants that remain immutable after initialization. A mutable integer is declared as var count: int = 0; count += 1, allowing changes, whereas let pi: float = 3.14 prevents reassignment to enforce safer code.[46] This distinction aids in tracking state changes in imperative code. Nim's effects system further refines this by requiring annotations on procedures to declare potential side effects, such as I/O operations or exceptions, which enables compiler optimizations like inlining pure functions.[47] For instance, proc readInput(): string {.tags: [IoEffect], raises: [IOError].} = ... specifies I/O involvement and possible errors, while {.noSideEffect.} marks procedures without external effects, such as proc square(x: int): int {.noSideEffect.} = x * x.[47]
Core imperative control structures include loops and conditionals for directing program flow. The while loop executes a block as long as a condition holds, e.g., var i = 0; while i < 5: i += 1, and the for loop iterates over ranges or collections, like for j in 1..3: echo j.[29] Conditionals use if for branching, such as if x > 0: echo "Positive" else: echo "Non-positive", and case for multi-way decisions, e.g., case day: of "Monday": echo "Start of week".[44] Iterators, declared with the iterator keyword, provide a procedural way to generate sequences on-the-fly, using yield to produce values lazily; for example, iterator countdown(n: int): int = while n > 0: yield n; n -= 1, which can be consumed in a for loop.[48]
For low-level control, Nim offers manual memory management options alongside its default garbage collection. The new procedure allocates heap memory for reference types, initializing them, as in var node: ref Node; new(node); node.value = 42.[49] Conversely, dispose explicitly frees untraced or manual allocations, such as dispose(pointer), providing fine-grained control for performance-critical imperative code.[49]
Object-oriented
Nim's object-oriented paradigm builds upon its record types, extending them to support inheritance, method attachment, and runtime type information for objects. Objects are defined similarly to records but provide additional capabilities, such as hiding fields from other modules and enabling inheritance hierarchies. Methods are attached to objects using themethod keyword, allowing for object-specific procedures that can be invoked via dot notation, such as obj.methodName(args). This design integrates seamlessly with Nim's type system, where objects serve as value types on the stack by default.[3]
For dynamic allocation and reference semantics, Nim uses ref object types, which allocate instances on the heap via the built-in new procedure. For example:
type
Node = ref object
data: int
next: Node
var n: Node
new(n)
n.data = 42
type
Node = ref object
data: int
next: Node
var n: Node
new(n)
n.data = 42
object of syntax, which establishes an is-a relationship and implicit subtyping. A child object inherits all fields and methods from its parent, and the child becomes a subtype of the parent, allowing it to be used wherever the parent type is expected. For instance:
type
[Animal](/page/Animal) = object of RootObj
name: string
[Dog](/page/Dog) = object of [Animal](/page/Animal)
breed: string
type
[Animal](/page/Animal) = object of RootObj
name: string
[Dog](/page/Dog) = object of [Animal](/page/Animal)
breed: string
ref object types, the method keyword enables dynamic (virtual) dispatch, where the actual method invoked is determined at runtime based on the object's dynamic type. This supports polymorphism in inheritance hierarchies, such as overriding a parent's method in a child object. Encapsulation is enforced through module-level visibility: object fields are private by default and inaccessible outside the defining module, but can be exported publicly by appending an asterisk (*) to the field name, e.g., publicField*: int. This explicit visibility control promotes modular design while avoiding accidental exposure of internal state.[3]
Functional
Nim supports functional programming through first-class functions, which allow procedures to be treated as values that can be assigned to variables, passed as arguments to other procedures, or returned from them. This enables composable code where functions serve as building blocks for higher-level abstractions. Procedures are defined using theproc keyword, and their first-class nature is inherent to Nim's type system for procedural types.[50]
Anonymous procedures, also known as lambdas, can be defined inline without a name, facilitating concise expressions for one-off functions. For example:
let add = proc (x, y: int): int = x + y
echo add(3, 4) # Outputs: 7
let add = proc (x, y: int): int = x + y
echo add(3, 4) # Outputs: 7
.closure. calling convention. This allows nested procedures to access and potentially modify outer variables, promoting flexible function creation. Partial application is achievable through higher-order functions and closures, where a function can be wrapped to fix some arguments, though Nim lacks built-in currying syntax.[51][50]
Immutability is encouraged in Nim to foster predictable, side-effect-free code. The let statement declares immutable variables that cannot be reassigned after initialization, ensuring values remain constant throughout their scope. For procedures, the func keyword defines pure functions that implicitly apply the {.noSideEffect.} pragma, guaranteeing no modifications to external state and dependence solely on input arguments. This is equivalent to declaring a proc with {.noSideEffect.}, enabling compiler optimizations and functional purity. For instance:
func add(a, b: int): int = a + b # Pure function, no side effects
func add(a, b: int): int = a + b # Pure function, no side effects
do notation, allowing chained transformations for readable, declarative code. The pipe operator |> (available via the sugar module or custom definition) passes the result of an expression as the first argument to the next function, enabling fluid pipelines. The do notation provides a syntactic sugar for supplying anonymous procedures to higher-order functions inline. An example of pipelining:
proc double(x: int): int = x * 2
echo 5 |> double # Outputs: 10
proc double(x: int): int = x * 2
echo 5 |> double # Outputs: 10
do with sorting:
proc sort[T](s: var seq[T], cmp: proc (x, y: T): int) = ...
var cities = @["London", "Tokyo", "Paris"]
sort(cities) do (x, y: string) -> int: cmp(x.len, y.len)
proc sort[T](s: var seq[T], cmp: proc (x, y: T): int) = ...
var cities = @["London", "Tokyo", "Paris"]
sort(cities) do (x, y: string) -> int: cmp(x.len, y.len)
type
NodeKind = enum nkInt, nkFloat
Node = ref object
case kind: NodeKind
of nkInt: intVal: int
of nkFloat: floatVal: float
type
NodeKind = enum nkInt, nkFloat
Node = ref object
case kind: NodeKind
of nkInt: intVal: int
of nkFloat: floatVal: float
case statements, which branch based on the discriminator for exhaustive or selective handling. Continuing the example:
proc printNode(n: Node) =
case n.kind
of nkInt: echo n.intVal
of nkFloat: echo n.floatVal
proc printNode(n: Node) =
case n.kind
of nkInt: echo n.intVal
of nkFloat: echo n.floatVal
map and filter in the sequtils module, operating on sequences for transformations and selections. The map function applies a given procedure to each element, producing a new sequence:
import sequtils
let nums = @[1, 2, 3]
let doubled = nums.map(proc (x: int): int = x * 2) # @[2, 4, 6]
import sequtils
let nums = @[1, 2, 3]
let doubled = nums.map(proc (x: int): int = x * 2) # @[2, 4, 6]
filter retains elements satisfying a predicate:
let evens = nums.filter(proc (x: int): bool = (x mod 2) == 0) # @[2]
let evens = nums.filter(proc (x: int): bool = (x mod 2) == 0) # @[2]
do notation for brevity, such as nums.filter do (x: int) -> bool: x > 1. They facilitate composable operations on collections without mutating originals.[58]
Concurrent and parallel
Nim provides support for concurrency and parallelism through a combination of low-level primitives and higher-level abstractions, emphasizing safety in shared memory access. The language's threads module enables OS-level threading. This allows creation of explicit threads viacreateThread, facilitating concurrent execution of independent tasks.[41]
For lightweight task parallelism, Nim offers the spawn primitive from the threadpool module, which schedules computations on a thread pool without blocking the caller, returning a FlowVar for synchronization and result retrieval. As of 2025, the standard threadpool has been deprecated in favor of community-maintained alternatives like malebolgia, taskpools, or weave for more robust parallel execution, addressing performance regressions observed in Nim 2.0.[59][60]
Cooperative concurrency is handled via the asyncdispatch module, which implements an event-driven dispatcher supporting async/await syntax for non-blocking I/O operations. This model relies on futures for deferred computations and channels for inter-task communication, enabling efficient handling of asynchronous events without OS threads. The select statement in the channels module further supports multiplexing, allowing a single thread to wait on multiple channels or async events and react to the first available one, similar to select in Unix systems.[61]
Parallelism can also be achieved using the parallel statement, which transforms loops or blocks into parallel executions, generating OpenMP directives when compiling to C for hardware-accelerated parallelism on multi-core systems. Manual thread pools provide finer control for custom parallel workloads.[62]
Nim employs a shared memory model where global variables and explicitly allocated shared objects reside on a process-wide heap, accessible across threads via allocShared. To prevent data races, mutability is managed carefully with synchronization primitives: the atomics module offers lock-free operations like load, store, exchange, and fetchAdd with configurable memory orders (e.g., moAcquireRelease), while the locks module provides mutexes (Lock) and condition variables (Cond) for guarded access, including the withLock template for scoped acquisition. Recent enhancements in Nim 2.0 include shared heap support under the ORC memory manager, with thread safety for shared data achieved through explicit synchronization using locks and atomic operations.[63][64][60]
In multi-threaded contexts, Nim's memory management integrates atomic operations to handle shared references, ensuring deterministic destruction without leaks in concurrent scenarios.[41]
Compiler and runtime
Compilation targets and process
The Nim compiler processes source code through a multi-stage pipeline that begins with lexical analysis and parsing to construct an abstract syntax tree (AST), followed by semantic analysis for type checking and resolution, and concludes with backend-specific code generation.[65] This pipeline ensures that Nim programs are transformed into intermediate representations suitable for various execution environments, emphasizing efficiency and portability.[5] The primary backend generates C code, which is then compiled into native executables using external compilers such as GCC, Clang, or MSVC, allowing Nim to produce high-performance binaries for desktop and server applications.[5] Alternative targets include JavaScript for web-based execution in browsers, enabling client-side scripting with Nim's syntax, and Objective-C for iOS and macOS app development, facilitating integration with Apple's ecosystem.[5] Other backends, such as C++, support specialized use cases like embedding in C++ projects.[65] Compiler flags provide fine-grained control over the build process; for instance,--opt:speed enables aggressive optimizations to prioritize runtime performance, while --mm:arc selects the Automatic Reference Counting memory model.[5] Cross-compilation is robustly supported across platforms including Windows, Linux, macOS, and embedded systems, achieved via options like --os:linux and --cpu:arm to target diverse architectures without a host toolchain for the destination.[5]
In debug modes, hot code reloading is available via --hotCodeReloading:on, allowing runtime updates to code without full restarts, particularly useful for interactive prototyping.[5]
Memory management
Nim employs a flexible memory management system that supports multiple strategies, allowing developers to select approaches suited to performance, determinism, and resource constraints via the--mm: compiler flag.[6]
The default strategy, introduced as the standard in Nim 2.0, is ORC (Optimized Reference Counting), which can be enabled via --mm:orc, a deterministic reference counting system with integrated cycle detection to handle circular references without garbage collection pauses.[6][66] ORC maintains a shared heap across threads, enabling efficient multi-threaded operation while ensuring predictable deallocation at scope exit.[6] An alternative Boehm garbage collector, which uses a conservative, stop-the-world mark-and-sweep algorithm on a shared heap, remains available as an optional choice for scenarios requiring simpler integration with legacy code.[6]
ARC (Automatic Reference Counting), a variant of ORC without cycle detection, offers even lower overhead for acyclic data structures and can be enabled via --mm:arc; it prioritizes minimal latency but may leak memory in the presence of cycles, such as those introduced by asynchronous code.[6] Both ARC and ORC, first experimentally available in Nim 1.4 and fully matured in 2.0, replace traditional garbage collection with compile-time reference tracking, ensuring deallocation occurs immediately when reference counts reach zero.[6][66] These models integrate destructors—procedures invoked via the =destroy hook—to automatically release non-memory resources like file handles or sockets upon object destruction.[8]
For fine-grained control, Nim supports manual memory management through untraced pointers declared with the ptr type, which bypass automatic tracking.[28] Developers can allocate heap memory using alloc or realloc from the system module and explicitly free it with dealloc, while new initializes traced reference objects on the heap (though deallocation is typically GC-handled unless --mm:none disables the collector entirely).[67] The dispose procedure provides a manual way to invoke destructors and free traced objects early.[67] Mixing manual and automatic management requires caution, such as using reset to clear GC-tracked fields before deallocating containing pointers, to prevent leaks or invalid accesses.[3]
To optimize performance under ARC/ORC, Nim implements sinking optimization through move semantics, which transfers ownership of resources without unnecessary copies.[68] This is facilitated by the =sink hook, allowing procedures to "steal" contents from source objects (marked as moved via =wasMoved) and leave them in a valid but empty state.[68] For example, sinking a sequence avoids duplicating its underlying buffer:
type MySeq = object
data: seq[int]
proc `=sink`(a: var MySeq; b: MySeq) =
type MySeq = object
data: seq[int]
proc `=sink`(a: var MySeq; b: MySeq) =
Transfer ownership without copy
shallow(a.data, b.data) # Or similar resource moveMark b as moved if needed
var s1 = MySeq(data: @[1, 2, 3]) var s2: MySeq s2 = s1 # Sinks: no copy of data
This reduces allocation overhead in functional-style code or when returning large objects.[](https://nim-lang.org/docs/destructors.html#move-semantics)
In concurrent programming, memory models like the legacy `--mm:refc` (deferred [reference counting](/page/Reference_counting) with mark-and-sweep backup) and `--mm:markAndSweep` utilize thread-local heaps to minimize contention and enable independent collection per thread, though this complicates [data sharing](/page/Data_sharing) across threads.[](https://nim-lang.org/docs/mm.html)[](https://nim-lang.org/docs/refc.html) ORC and ARC, by contrast, employ a shared heap with atomic [reference counting](/page/Reference_counting) for thread safety, avoiding per-thread isolation while preserving determinism.[](https://nim-lang.org/docs/mm.html)
The ARC/ORC models trade traditional garbage collection's simplicity for enhanced control, offering sub-millisecond pauses suitable for real-time systems but necessitating explicit [destructors](/page/The_Destructors) for resource cleanup to prevent leaks in non-memory contexts.[](https://nim-lang.org/docs/mm.html)[](https://nim-lang.org/docs/destructors.html) In exchange, they eliminate stop-the-world events inherent in Boehm-style collectors, at the cost of slightly higher compile-time analysis for [cycle detection](/page/Cycle_detection) in ORC.[](https://nim-lang.org/docs/mm.html) Disabling the collector entirely (`--mm:none`) grants maximum performance for embedded or systems code but demands rigorous manual oversight to avoid memory exhaustion.[](https://nim-lang.org/docs/mm.html)
### Foreign function interface
Nim's foreign function interface (FFI) enables seamless [interoperability](/page/Interoperability) with code written in other languages, primarily through its [C](/page/C) backend, allowing developers to leverage existing libraries without significant performance overhead. The FFI is centered on direct integration with [C](/page/C), where Nim procedures and variables can be marked for import using the `importc` pragma, which declares them as external entities from [C](/page/C) code. For instance, to call the standard [C](/page/C) `printf` function, one defines:
```nim
proc printf(formatstr: cstring; args: varargs[pointer]) {.importc: "printf",
varargs, header: "<stdio.h>".}
This reduces allocation overhead in functional-style code or when returning large objects.[](https://nim-lang.org/docs/destructors.html#move-semantics)
In concurrent programming, memory models like the legacy `--mm:refc` (deferred [reference counting](/page/Reference_counting) with mark-and-sweep backup) and `--mm:markAndSweep` utilize thread-local heaps to minimize contention and enable independent collection per thread, though this complicates [data sharing](/page/Data_sharing) across threads.[](https://nim-lang.org/docs/mm.html)[](https://nim-lang.org/docs/refc.html) ORC and ARC, by contrast, employ a shared heap with atomic [reference counting](/page/Reference_counting) for thread safety, avoiding per-thread isolation while preserving determinism.[](https://nim-lang.org/docs/mm.html)
The ARC/ORC models trade traditional garbage collection's simplicity for enhanced control, offering sub-millisecond pauses suitable for real-time systems but necessitating explicit [destructors](/page/The_Destructors) for resource cleanup to prevent leaks in non-memory contexts.[](https://nim-lang.org/docs/mm.html)[](https://nim-lang.org/docs/destructors.html) In exchange, they eliminate stop-the-world events inherent in Boehm-style collectors, at the cost of slightly higher compile-time analysis for [cycle detection](/page/Cycle_detection) in ORC.[](https://nim-lang.org/docs/mm.html) Disabling the collector entirely (`--mm:none`) grants maximum performance for embedded or systems code but demands rigorous manual oversight to avoid memory exhaustion.[](https://nim-lang.org/docs/mm.html)
### Foreign function interface
Nim's foreign function interface (FFI) enables seamless [interoperability](/page/Interoperability) with code written in other languages, primarily through its [C](/page/C) backend, allowing developers to leverage existing libraries without significant performance overhead. The FFI is centered on direct integration with [C](/page/C), where Nim procedures and variables can be marked for import using the `importc` pragma, which declares them as external entities from [C](/page/C) code. For instance, to call the standard [C](/page/C) `printf` function, one defines:
```nim
proc printf(formatstr: cstring; args: varargs[pointer]) {.importc: "printf",
varargs, header: "<stdio.h>".}
cint for C's int, cchar for char, pointer for generic pointers, and cstring for null-terminated C strings (equivalent to char*). The cstring type is particularly useful but requires caution, as it lacks automatic memory management and can lead to issues if Nim strings are converted implicitly without ensuring zero-termination. More complex C structures, such as arrays or unions, map to Nim's array, seq, or object types, often requiring manual adjustment for full fidelity.[3]
Calling conventions are specified via pragmas to match those of the foreign code, ensuring correct argument passing and stack cleanup. The cdecl pragma adopts the standard C convention, where the caller handles stack cleanup, suitable for most Unix-like systems; under Windows, it generates __cdecl declarations. For Windows API compatibility, stdcall uses the callee-cleaned stack model, producing __stdcall. These are combined with importc, as in:
proc messageBox(hWnd: pointer; text, caption: cstring; uType: uint32): cint
{.importc: "MessageBoxA", stdcall, header: "<windows.h>".}
proc messageBox(hWnd: pointer; text, caption: cstring; uType: uint32): cint
{.importc: "MessageBoxA", stdcall, header: "<windows.h>".}
cdecl unless overridden.[3]
To automate wrapper generation from C headers, Nim includes the official c2nim tool, which translates ANSI C code into readable Nim equivalents for manual refinement. It processes header files, handling defines, structs, and enums—e.g., converting #define MAX 100 to const MAX* = 100—while including a preprocessor for complex inputs. Installation via Nimble (nimble install c2nim) enables quick prototyping of FFI bindings, though users often tweak the output for Nim idioms like generics or safety.[69]
Beyond C, Nim supports other languages through intermediaries or direct pragmas. For C++, the importcpp pragma allows importing classes, templates, and functions, using placeholders like @ for arguments:
type Vector[T] {.importcpp: "std::vector<'0>", header: "<vector>".} = object
proc newVector[T](): Vector[T] {.importcpp: "std::vector<'0>(@)".}
type Vector[T] {.importcpp: "std::vector<'0>", header: "<vector>".} = object
proc newVector[T](): Vector[T] {.importcpp: "std::vector<'0>(@)".}
std::vector, with support for constructors and destructors. For languages like Python, interop occurs via C's Python API using libraries such as nimpy, which provides bidirectional bindings by embedding Python interpreters or extending Python with Nim modules. JavaScript interop leverages Nim's JS backend directly. These approaches rely on C as a bridge where native support is absent.[3][70]
Safety in FFI calls emphasizes developer responsibility, as Nim's runtime protections like garbage collection do not extend to foreign code. Bounds checking, enabled by default for Nim arrays and sequences, can be disabled globally via --boundChecks:off or per-procedure with the noBoundsCheck pragma to match C's unchecked access, reducing overhead but risking buffer overflows. The cstring type explicitly omits bounds checking during indexing to mimic C behavior, and pointers in FFI require manual null checks to avoid crashes. Pragmas like gcsafe ensure foreign procedures do not interact unexpectedly with Nim's collector.[3]
Development tools
Bundled tools
The Nim programming language distribution includes a suite of bundled tools designed to support core development tasks, such as package management, code analysis, formatting, testing, and integration with external codebases. These utilities are provided alongside the compiler to streamline workflows for Nim developers, ensuring portability and consistency without reliance on external dependencies.[71] Nimble serves as the default package manager for Nim, enabling users to search for packages, install dependencies, create new projects, and upload libraries to the official repository at nimble.directory. It is integrated into the Nim installation and requires Git for handling repository-based packages.[72] Atlas is a simple package cloner tool that manages project dependencies in an isolated deps/ directory, compatible with Nimble for handling workspaces and dependencies.[73] c2nim is a converter tool that translates C and C++ header files into equivalent Nim modules, facilitating interoperability with existing C libraries by generating Nim wrappers. This allows developers to bind to C code while maintaining Nim's type safety and syntax. koch acts as the primary maintenance script for the Nim project, used to build the compiler, generate documentation, and perform other build-related tasks as a portable alternative to traditional makefiles or shell scripts. It supports commands for bootstrapping, testing, and website generation within the Nim repository.[74] nimgrep provides a grep-like utility tailored for searching and replacing patterns within Nim source code files, supporting regular expressions and handling Nim-specific syntax for efficient code navigation and refactoring.[75] nimsuggest enables IDE integration by querying Nim source files to deliver information such as symbol definitions, autocompletion suggestions, and navigation aids, allowing editors to offer real-time development support. It operates as a server process that responds to protocol-based requests from compatible tools.[76] niminst generates installers for Nim programs and packages, producing self-contained executables or scripts suitable for distribution across platforms like Windows, Linux, and macOS. It handles dependency resolution and packaging to simplify deployment.[77] nimpretty is a source code beautifier that automatically formats Nim code according to the official style guide, promoting consistent readability and adherence to community conventions during development and maintenance.[71] Testament functions as an advanced testing framework for Nim, running unit tests with features like process isolation, support for multiple compilation targets (e.g., C, JavaScript), detailed logging, HTML report generation, and conditional test skipping based on configuration. It integrates seamlessly with Nim's module system for comprehensive validation of codebases.[78]Third-party tools
The Nim ecosystem benefits from a variety of community-developed tools that enhance productivity and integration capabilities beyond the standard compiler distribution. These third-party tools address specific needs such as version management, language bridging, and automated code generation, fostering a flexible development environment for Nim users.[18] Choosenim serves as a version manager that simplifies the installation and switching between multiple Nim compiler releases, including stable and development versions sourced directly from official downloads. It allows developers to maintain isolated environments for different projects, preventing compatibility issues during upgrades or experimentation with bleeding-edge features. By automating the download, compilation, and activation of Nim versions via a simple command-line interface, choosenim streamlines workflow in multi-version setups.[79] Nimpy provides a robust bridge for integrating Python code within Nim programs or exposing Nim functionality to Python scripts, enabling seamless data exchange between the two languages. It handles type conversions, such as transforming Nim strings into Python-compatible formats while managing encoding challenges like invalid UTF-8 sequences by falling back to byte strings. This tool is particularly useful for leveraging Python's extensive libraries in Nim applications or vice versa, with support for embedding Python interpreters directly in Nim binaries.[70] Pixie is a comprehensive 2D graphics library that includes tooling for image processing and vector operations, akin to established libraries like Cairo and Skia. It supports rasterization tasks such as cropping, shape drawing, and text rendering, all implemented natively in Nim for high performance without external dependencies. Developers can use Pixie's utilities to build graphical applications, prototypes, or utilities for image manipulation, with ongoing active development ensuring compatibility with evolving Nim features.[80] Nimterop automates the generation of wrappers for C and C++ libraries, making foreign function interface (FFI) integration more efficient by parsing header files with the tree-sitter engine. It converts relevant abstract syntax tree (AST) portions from C/C++ into Nim-compatible definitions, reducing manual boilerplate and error-prone header translations. This tool excels in large-scale interop scenarios, such as binding complex C++ APIs, and supports customizable output to align with Nim's type system.[81] Arraymancer offers a toolkit for numerical computing, featuring tensor operations with support for BLAS (Basic Linear Algebra Subprograms) acceleration on CPU, CUDA, and OpenCL backends. It provides ergonomic abstractions for multidimensional arrays, enabling efficient data processing in scientific and machine learning contexts without sacrificing Nim's performance characteristics. The library's tooling includes utilities for tensor manipulation, linear algebra, and optimization routines, making it suitable for high-throughput computations.[82] Jester functions as a lightweight web framework with integrated server tooling, modeled after Sinatra to facilitate rapid development of HTTP-based applications in Nim. It employs a domain-specific language (DSL) for defining routes, handling requests, and managing responses, including built-in support for middleware and templating. This setup allows developers to deploy full web servers with minimal configuration, ideal for APIs, microservices, or prototyping.[83] Nimporter is an advanced tool for Python-Nim integration, building on Nimpy to compile and import Nim extensions dynamically during Python module loading. It addresses packaging challenges by automating the build process for Nim code as Python extensions, enabling hybrid applications to leverage Nim's speed within Python ecosystems seamlessly. This update enhances cross-language deployment, particularly for data-intensive projects requiring low-level optimizations.[84]Libraries and ecosystem
Standard library
Nim's standard library comprises a collection of modules that provide essential functionality for general-purpose programming, categorized into pure libraries, impure libraries, and wrappers. Pure libraries are self-contained and do not rely on external binaries such as DLLs or shared objects, ensuring portability and predictability; examples include modules for string handling and mathematical operations. Impure libraries, in contrast, depend on system-specific binaries for tasks involving input/output or external integrations, while wrappers offer low-level interfaces to C libraries for advanced system access. This division allows developers to select modules based on the need for purity in functional paradigms versus practical side effects in imperative code.[85] Core modules form the foundation of Nim programming. Thesystem module, implicitly imported in every Nim file, supplies built-in procedures, types, and constants essential for basic language operations, such as type conversions and runtime checks. The strutils module delivers a suite of string manipulation functions, including splitting, joining, and formatting, optimized for efficiency in text processing. Complementing sequences—Nim's dynamic arrays—the sequtils module offers higher-order functions like mapping, filtering, and folding, enabling concise functional-style programming on collections. For numerical computations, the math module provides constants (e.g., π, e), trigonometric functions, and statistical utilities, supporting both integer and floating-point arithmetic with high precision.[41]
Input/output and operating system interactions are handled by dedicated modules in the impure category. The os module exposes cross-platform facilities for file and directory operations, environment variables, and process management, abstracting POSIX and Windows APIs to simplify system-level programming. The streams module implements abstract I/O streams for reading and writing data in a buffered, sequential manner, compatible with both files and in-memory sources. Networking capabilities are supported by the httpclient module, which facilitates synchronous and asynchronous HTTP requests, including support for headers, proxies, and SSL/TLS, making it suitable for web-based applications.[86]
Data structures in the standard library emphasize efficiency and generality. The tables module implements ordered and unordered hash tables for key-value storage, with features like automatic resizing and collision resolution to handle large datasets. The sets module provides ordered sets with operations such as union, intersection, and difference, leveraging hash tables for O(1) average-time complexity. For queue-like operations, the deques module offers double-ended queues that support efficient appends and pops from both ends, ideal for breadth-first searches or task scheduling. These structures are pure where possible, promoting composability without side effects.
The distinction between pure and impure modules underscores Nim's support for side-effect-free programming. Pure modules, such as strutils, sequtils, and math, avoid I/O operations and global state modifications, aligning with functional programming principles by ensuring referential transparency and thread safety. Impure modules, like os and streams, incorporate side effects for real-world interactions, such as file access or network calls, but are designed to be contained within delimited scopes to minimize risks in concurrent environments. This separation enables developers to mix paradigms while maintaining code reliability.[85]
Concurrency and asynchronous programming are addressed through specialized modules. The threads module enables low-level multithreading with primitives for thread creation, synchronization via locks and conditions, and shared memory access, built on platform-native threading libraries. For event-driven I/O, asyncdispatch provides a dispatcher for asynchronous procedures, integrating with selectors for efficient polling of file descriptors and sockets. The channels module facilitates safe communication between threads or async tasks using buffered or unbuffered channels, inspired by Go's design but adapted to Nim's memory model for zero-copy transfers where possible. These modules are impure due to their reliance on OS threading and I/O primitives.
Recent versions of Nim have expanded the standard library's capabilities. The standard library includes hashing modules such as md5 and sha1 under the hashes category for secure hashing primitives, available since earlier versions; advanced encryption like AES is supported via external libraries. The json module received significant improvements in version 2.2 (released in 2024), featuring a high-performance parser and builder for handling large JSON datasets with reduced memory footprint and faster serialization. Nim 2.2.6, released in October 2025, includes further stability improvements but no major new stdlib modules. These additions reflect ongoing efforts to bolster Nim's utility for secure and data-intensive applications without external dependencies.[22][24]
Package management and external libraries
Nimble serves as the primary package manager for the Nim programming language, facilitating the discovery, installation, and management of third-party libraries and dependencies.[72] Developers can install packages using thenimble install <package> command, which downloads and compiles the specified library from repositories like GitHub, while nimble develop <package> enables local development by symlinking the package source for editing without full installation.[72] This tool integrates seamlessly with Nim's build process, automatically resolving transitive dependencies—those required by installed packages—and supporting version pinning in configuration files to lock specific library versions for reproducibility.[72]
Build configurations for Nim projects, including dependency management, are often defined using NimScript in files named build.nims.[87] NimScript, a subset of the Nim language interpreted by the compiler's virtual machine, allows declarative setup of compilation flags, tasks, and hooks, such as pre- or post-build actions, without requiring a full Nim compilation for the build script itself.[87] This approach provides flexibility for complex projects while maintaining compatibility with Nimble's dependency resolution.
External libraries in Nim are categorized as pure or impure, mirroring the standard library's distinctions: pure libraries are implemented entirely in Nim without relying on external binaries or foreign code, ensuring portability across compilation targets, whereas impure libraries interface with system-level dependencies like C libraries via Nim's foreign function interface.[85] For example, Jester is a popular pure web framework inspired by Sinatra, offering a domain-specific language for routing and handling HTTP requests in server-side applications.[83] Karax provides a framework for building single-page JavaScript frontends directly in Nim, compiling to efficient browser code.[88] Chronos, an asynchronous programming library, supports event loops and futures for concurrent I/O operations, often used in networked applications.[89]
Packages are discovered through the official Nim Package Directory, which indexes over 2,500 libraries as of 2025, as well as GitHub repositories under the nim-lang organization and discussions on the Nim forum.[90][91][92] The 2024 Nim community survey highlighted ecosystem growth, with 28% of respondents using Nim for over 60% of their work (up from 20% in 2023) and 57% having two or more years of experience, though availability of specialized libraries remains a key barrier cited by non-adopters.[93]
Code examples
Basic examples
To illustrate Nim's straightforward syntax for imperative programming, consider a basic "Hello, World!" program that uses theecho procedure from the standard library to output text to the console.[94]
echo "Hello, World!"
echo "Hello, World!"
let and mutable ones with var; types can be explicitly annotated or inferred from initializers.[52][95]
let message = "immutable string" # Type inferred as string
var count: int = 42 # Explicit int type, mutable
count = 43 # Reassignment allowed
echo message, " has length ", count
let message = "immutable string" # Type inferred as string
var count: int = 42 # Explicit int type, mutable
count = 43 # Reassignment allowed
echo message, " has length ", count
return statement.[94]
proc [factorial](/page/Factorial)(n: int): int =
if n <= 1:
return 1
return n * [factorial](/page/Factorial)(n - 1)
echo [factorial](/page/Factorial)(5) # Outputs 120
proc [factorial](/page/Factorial)(n: int): int =
if n <= 1:
return 1
return n * [factorial](/page/Factorial)(n - 1)
echo [factorial](/page/Factorial)(5) # Outputs 120
proc fib(n: int): int =
var a = 0
var b = 1
if n < 2:
return n
for i in 2..<n+1:
let next = a + b
a = b
b = next
return b
echo fib(10) # Outputs 55
proc fib(n: int): int =
var a = 0
var b = 1
if n < 2:
return n
for i in 2..<n+1:
let next = a + b
a = b
b = next
return b
echo fib(10) # Outputs 55
proc reverse(s: string): string =
result = newString(s.len)
for i in 0..<s.len:
result[i] = s[s.len - 1 - i]
echo reverse("Nim") # Outputs "miN"
proc reverse(s: string): string =
result = newString(s.len)
for i in 0..<s.len:
result[i] = s[s.len - 1 - i]
echo reverse("Nim") # Outputs "miN"
Advanced examples
This section presents advanced code examples that integrate multiple Nim features, such as libraries, concurrency primitives, generics, metaprogramming, and foreign function interfaces, to illustrate practical applications in real-world scenarios. These examples build on Nim's multi-paradigm capabilities, combining object-oriented, functional, and procedural elements for more complex tasks.Graphical user interface
Nim supports cross-platform GUI development through third-party libraries like nimx, which provides a declarative layout system and event handling. The following example creates a simple window with a label using nimx, demonstrating how to set up an application entry point and basic view hierarchy. This integrates Nim's object system with the library's API for rendering a "Hello, world!" message in a resizable window.[98]import nimx/[window, label, types, layout]
app.appName = "Simple Nimx Window"
proc main() =
var wnd = newWindow(newRect(40, 40, 800, 600))
wnd.makeLayout:
- Label:
frame == super
text: "Hello, world!"
textColor: blackColor()
fontSize: 24
runApplication:
main()
import nimx/[window, label, types, layout]
app.appName = "Simple Nimx Window"
proc main() =
var wnd = newWindow(newRect(40, 40, 800, 600))
wnd.makeLayout:
- Label:
frame == super
text: "Hello, world!"
textColor: blackColor()
fontSize: 24
runApplication:
main()
nimble install nimx) and use nim c --run yourfile.nim for desktop targets (adjust backend as needed for iOS/Android/WebAssembly). This approach leverages Nim's garbage collection for safe memory handling in UI components.[98]
Concurrent task
Nim's asyncdispatch module enables efficient concurrency for I/O-bound operations, such as HTTP requests, while futures facilitate safe data exchange between concurrent tasks. The example below fetches content asynchronously from a URL using the httpclient library and completes a future with the result to a receiver, combining async/await with non-blocking communication to avoid blocking the main event loop. This pattern is useful for building responsive servers or data pipelines.[86]import std/[asyncdispatch, httpclient]
var ch = newFuture[string]()
proc fetchContent(url: string, fut: Future[string]) {.async.} =
var client = newAsyncHttpClient()
defer: client.close()
let content = await client.getContent(url)
fut.complete(content)
proc main() {.async.} =
asyncSpawn fetchContent("http://example.com", ch)
let result = await ch
echo "Fetched: ", result.len, " bytes"
waitFor main()
import std/[asyncdispatch, httpclient]
var ch = newFuture[string]()
proc fetchContent(url: string, fut: Future[string]) {.async.} =
var client = newAsyncHttpClient()
defer: client.close()
let content = await client.getContent(url)
fut.complete(content)
proc main() {.async.} =
asyncSpawn fetchContent("http://example.com", ch)
let result = await ch
echo "Fetched: ", result.len, " bytes"
waitFor main()
asyncSpawn schedules the fetch without blocking, and the future ensures the content is delivered to the main proc. For production, add error handling with try/except around the await expressions. This integrates functional composition (async procs) with imperative control flow.[86]
Generic data structure
Nim's generics allow type-safe reusable data structures, while pattern matching via the case statement enables destructuring and conditional logic on variants or collections. The following implements a generic stack using a sequence, with push/pop operations and pattern matching to handle empty/non-empty states, demonstrating functional safety checks integrated with object-oriented encapsulation. This example draws from Nim's built-in collection types and control flow for robust implementation.[99][57]type
Stack*[T] = object
data: seq[T]
proc initStack*[T](): Stack[T] =
result.data = @[]
proc push*[T](s: var Stack[T]; item: T) =
s.data.add(item)
proc pop*[T](s: var Stack[T]): T =
case s.data.len
of 0:
raise newException(IndexError, "Stack is empty")
else:
result = s.data[^1]
s.data.del(s.data.len - 1)
# Usage
var intStack = initStack[int]()
intStack.push(1)
intStack.push(2)
echo pop(intStack) # Outputs: 2
type
Stack*[T] = object
data: seq[T]
proc initStack*[T](): Stack[T] =
result.data = @[]
proc push*[T](s: var Stack[T]; item: T) =
s.data.add(item)
proc pop*[T](s: var Stack[T]): T =
case s.data.len
of 0:
raise newException(IndexError, "Stack is empty")
else:
result = s.data[^1]
s.data.del(s.data.len - 1)
# Usage
var intStack = initStack[int]()
intStack.push(1)
intStack.push(2)
echo pop(intStack) # Outputs: 2
s.data.len provides exhaustive checking at compile-time for known ranges, enhancing reliability in generic contexts. For more advanced destructuring, libraries like fusion extend this with object/tuple matching.[99][100]
Macro usage
Nim's macro system enables powerful metaprogramming for domain-specific languages (DSLs) or code generation, such as automatic logging around expressions. The example defines a simple logging macro that wraps its argument in an echo statement with a timestamp, transforming the AST at compile-time to insert debug output without runtime overhead when disabled. This combines reflection (via quote do) with procedural generation for concise, expressive code.[101]import std/[macros, times]
macro log(body: untyped): untyped =
quote do:
when declared(debugLog):
let ts = now().format("yyyy-MM-dd HH:mm:ss")
echo "[" & ts & "] Log: ", `body`
else:
`body`
const debugLog = true # Toggle for production
log("Application started") # Expands to echo with timestamp
import std/[macros, times]
macro log(body: untyped): untyped =
quote do:
when declared(debugLog):
let ts = now().format("yyyy-MM-dd HH:mm:ss")
echo "[" & ts & "] Log: ", `body`
else:
`body`
const debugLog = true # Toggle for production
log("Application started") # Expands to echo with timestamp
debugLog is true, invocations expand to logging calls; otherwise, they inline directly. This macro supports typed arguments for type safety and can be extended to capture caller info using getAst. For DSLs, similar techniques generate boilerplate like serialization code.[101]
FFI call
Nim's foreign function interface (FFI) seamlessly integrates C libraries via pragmas, allowing direct calls to system APIs like stdio for low-level file I/O. The example below imports C's fopen/fclose for reading a file, wrapping pointers in Nim procs for safe usage, and demonstrates how to link against libc without wrappers. This is compiled with--passC:-lc and highlights Nim's C backend for performance-critical interop.[102]
import std/os # For getCurrentDir
{.push header: "<stdio.h>".}
type FILE = pointer
proc fopen(filename, mode: cstring): ptr FILE {.importc.}
proc fread(ptr: pointer; size, n: int; file: ptr FILE): int {.importc.}
proc fclose(file: ptr FILE): int {.importc.}
{.pop.}
proc readFileC(filename: string): string =
let cFilename = filename.cstring
let file = fopen(cFilename, "r".cstring)
if file == nil:
raise newException(IOError, "Cannot open file")
defer: discard fclose(file)
let buffer = alloc(1024) # Simple fixed buffer for demo
let bytesRead = fread(buffer, 1, 1024, file)
result = newString(bytesRead)
copyMem(result[0].unsafeAddr, buffer, bytesRead)
dealloc(buffer)
echo readFileC("example.txt")
import std/os # For getCurrentDir
{.push header: "<stdio.h>".}
type FILE = pointer
proc fopen(filename, mode: cstring): ptr FILE {.importc.}
proc fread(ptr: pointer; size, n: int; file: ptr FILE): int {.importc.}
proc fclose(file: ptr FILE): int {.importc.}
{.pop.}
proc readFileC(filename: string): string =
let cFilename = filename.cstring
let file = fopen(cFilename, "r".cstring)
if file == nil:
raise newException(IOError, "Cannot open file")
defer: discard fclose(file)
let buffer = alloc(1024) # Simple fixed buffer for demo
let bytesRead = fread(buffer, 1, 1024, file)
result = newString(bytesRead)
copyMem(result[0].unsafeAddr, buffer, bytesRead)
dealloc(buffer)
echo readFileC("example.txt")