Nim CHEAT SHEET

The Nim quick reference cheat sheet that aims at providing help on writing basic syntax and methods.

15
Sections
76
Cards

#Getting Started

helloworld.nim
echo "Hello World!"

# This is a comment
echo "What's your name? "
var name: string = readLine(stdin)
# readLine(stdin) asks you to type in a string.

echo "Hi, ", name, "!"

Compile helloworld.nim with nim compile

$ nim compile helloworld.nim

Run the compiled binary helloworld (or helloworld.exe if you're on Windows)

./helloworld
Hello, World!
What's your name?
Hi, <name>!

There is also a possibility to both compile and run the program with just one command. We need to type: $ nim c -r helloworld.nim

Common compile commands (terminal)

nim c -r main.nim          # debug build, run after compile
nim c -d:release main.nim  # optimized release build
nim c --mm:arc main.nim    # ARC memory management (Nim 2 default)
Useful Resources
Variables
# 'var' declares mutable variables.

var number: int = 100 # Single line declaration

# A 'var' block can declare multiple variables at once.

var
  letter: char = 'n'
  lang = "N" & "im"
  length = len(lang)
  counter: int = 7
  boat: float
  truth = true
Immutable Variables (let)
# 'let' declares immutable variables.
let
  salute: string = "Hello!"
  x: int = 10
  y = x + 5

let z = 20
z = 500   # Error: 'z' is immutable
Comments
# This is a comment

#[
  This is a multiline comment.
  In Nim, multiline comments can be nested, beginning with #[
  ... and ending with ]#
]#
Constants
const
  debug = true
  compileBadCode = false

# Constants are declared at compile time and cannot be changed.
"For" Loops
for item in (1 ..< 6):
  if item == 3: break
  echo item

echo "All done!"

See: Loops

If Statements
import std/strutils
let number = parseInt(readLine(stdin))

if number <= 5:
  echo "Small sized number."
elif number > 5 and number <= 25:
  echo "Medium sized number."
else:
  echo "Big number."

See: Flow Control

Procedures / Functions
proc myFunction() =
  echo "Hello, this is my function"

myFunction()

# prints "Hello, this is my function"

See: Procedures

Formatted Strings
import std/strformat

let
  a = "Hello there."
  b = "How's it going?"
  c = "These are variables."

echo fmt"{a} {b} {c}" # "Hello there. How's it going? These are variables."

See: Imports

#Data Types

Integers
let
  a = 11
  b = 4

echo "a + b = ", a + b # 15
echo "a - b = ", a - b # 7
echo "a * b = ", a * b # 44
echo "a / b = ", a / b # 2.75
echo "a div b = ", a div b # 2
echo "a mod b = ", a mod b # 3
Floats
let
  c = 6.75
  d = 2.25

echo "c + d = ", c + d # 9.0
echo "c - d = ", c - d # 4.5
echo "c * d = ", c * d # 15.1875
echo "c / d = ", c / d # 3.0
Strings
let
  m = "word"
  n = "A sentence with punctuation."
  o = ""
  p = "32"
  q = "!"

echo m
# prints "word"
echo p, " is a string."
# prints "32 is a string."

String Concatenation

var
  p = "abc"
  q = "xy"
  r = 'z'

p.add("def")   # modifies p
q.add(r)       # chars can be added to strings

echo p         # "abcdef"
echo q         # "xyz"

# `&` creates a new string:
echo p & q     # "abcdefxyz"

Special Escape Sequences

echo "line1\nline2"     # newline
echo "col1\tcol2"       # tab
echo "A\\B\\C"          # backslash

# Raw strings ignore escapes:
echo r"line1\nline2"

See also: Escape Sequences

Characters
let
  h = 'z'
  i = '+'
  j = '2'
  k = '35'   # error: too many characters
  l = 'xy'   # error: too many characters
Booleans
let x = true
let y = false

# Boolean literals are lowercase.
Type Conversion

let e = 5
let f = 23.987

# Converting between ints and floats:
echo float(e)    # 5.0
echo int(f)      # 23

# Mixed operations require explicit conversion:
echo float(e) + f    # 28.987
echo e + int(f)      # 28

#Compound Types

Arrays
type IntArray = array[0..3, int]

let a: IntArray = [10, 20, 30, 40]

echo a[0]      # 10
echo a.len     # 4
Sequences
var s: seq[int] = @[1, 2, 3]
s.add(4)

echo s         # @[1, 2, 3, 4]
echo s.len     # 4
Objects
type Person = object
  name: string
  age: int

let p = Person(name: "Ana", age: 20)
echo p.name
Tuples
var person = (name: "Sophie", age: 18)

echo person.name # Sophie
echo person.age  # 18

# swapping values:
var (x, y) = (1, 2)
(x, y) = (y, x)
echo x, " ", y     # 2 1
Sets
type CharSet = set[char]

let letters: CharSet = {'a'..'z'}

echo 'a' in letters    # true
echo 'Z' in letters    # false
Reference Objects
type Node = ref object
  value: int
  next: Node     # linked list style

var n = Node(value: 10)
echo n.value

Needed for Object Oriented Programming within Nim.

Slicing Sequences and Strings
let xs = @[10, 20, 30, 40]

echo xs[1..2]    # @[20, 30]
echo xs[^2..^1]  # @[30, 40]

let s = "abcdef"

echo s[0..2]     # "abc"
echo s[3..^1]    # "def" (^1 = last char)
echo s[1..<4]    # "bcd"
Tables/Dictionaries
import std/tables

var ages = initTable[string, int]()
ages["Ana"] = 20
ages["Sophie"] = 18

echo ages["Ana"]                 # 20
echo ages.getOrDefault("X", -1)  # -1

for name, age in ages:
  echo name, ": ", age

#Operators

Arithmetic Operators
var
  a = 10
  b = 3

echo a + b      # 13
echo a - b      # 7
echo a * b      # 30
echo a / b      # 3.333333
echo a div b    # 3
echo a mod b    # 1
echo a ^ b      # 1000

OperatorNameExample
+Addx + y
-Subtractx - y
*Multiplyx * y
/Float Dividex / y
divInteger Dividex div y
modModulox mod y
^Powerx ^ y

{.show-header}

Assignment

These only work on mutable (var) variables, not on let or const.

var value = 1990
echo value # 1990

value = 2
echo value # 2

OperatorDescriptionExample
=Assign valuex = y

{.show-header}

Update operations

SyntaxExpands toMeaning
x += yx = x + yadd, assign
x -= yx = x - ysubtract, assign
x *= yx = x * ymultiply, assign

{.show-header}

Other variants like /= or mod= are not available,
so just write them out explicitly, e.g. x = x / y.

Comparison Operators
let
  x = 5
  y = 3

echo x > y
# prints "true" because 5 is greater than 3

SymbolMeaningExample
==equalsif x == y...
!=not equal toif x != y...
>greater thanif x > y...
<less thanif x < y...
>=greater than or equal toif x >= y...
<=less than or equal toif x <= y...

{.show-header}

Comparison operators are used to compare two values.

Lexicographical Comparison

They also work on char and string values via lexicographic order.

echo "apple" < "banana"  # true
echo "axyz" < "axyb"     # true
echo "ooooo" > "o"       # true
echo "abc" < "ab"        # false

echo 'a' < 'd'           # true
echo 'a' < 'Z'           # false
Logical Operators
OperatorExampleMeaning
andif a > 0 and a < 10:From 1 to 9
orif x == 0 or y == 0:Either one of them is 0
notif not isValid:If isValid is not true
xorif flagA xor flagB:Only one of them is true

{.show-header}

Logical operators work on bool.

Extra Bitwise Operators

OperatorExampleResult (with a = 60, b = 13)
anda and b12
ora or b61
xora xor b49
notnot a-61
shla shl 2240
shra shr 215

{.show-header}

These work on integers bit-by-bit; use them for flags, masks, low-level code, etc.

#Flow Control

Match Case
let x = 5
case x:
of 0, 1:
  echo "small"
of 2, 3, 4:
  echo "medium"
else:
  echo "large"

case of can look for ranges too.

let age = 17

case age:
of 0..12:
  echo "child"
of 13..19:
  echo "teen"
else:
  echo "adult"

...and strings and chars, too

let cmd = "quit"

case cmd:
of "help":
  echo "show help"
of "quit", "exit":
  echo "bye!"
else:
  echo "unknown command"

let ch = 'g'
case ch:
of {'a', 'e', 'i', 'o', 'u'}:
  echo "vowel"
else:
  echo "consonant or symbol"
Basic If-Else
let num = 5

if num > 10:
  echo "num is bigger than 10"
elif num < 10:
  echo "num is smaller than 10"
else:
  echo "num is exactly 10"
One Liners
let
  a = 330
  b = 200

let r = if a > b: a else: b

echo r # 330
Compile-Time Conditions
when defined(linux):
  echo "Compiled on Linux"
elif defined(windows):
  echo "Compiled on Windows"
else:
  echo "Unknown OS"

#Loops

For Loops
for i in 1..5:
  echo i
# 1 2 3 4 5

for i in 0..<3:
  echo i
# 0 1 2

# i = index, v = value in sequence
for i, v in @[10, 20, 30]:
  echo i, ": ", v
# 0: 10
# 1: 20
# 2: 30

Keep in mind:
1..5 = Inclusive (1 2 3 4 5)
1..<5 = Exclusive (1 2 3 4)

While Loops
var counter = 0

while counter <= 10:
  counter = counter + 1
  echo counter # prints 1..10
Infinite Loops
while true:
  echo "ay! "

while 1 > 0:
  echo "echo... "
Break Statements
var query = ""
while true:
  echo "Do you want out?"
  query = readLine(stdin)
  if query == "yes":
    echo "Well then."
    break
  else:
    echo "I'll ask again."

Continue Statements
for i in 1..5:
  if i mod 2 == 0: continue
  echo i
# prints only odd numbers: 1 3 5

#Procedures

Simple Procedure
proc salute() =
  echo "Hello!"

salute() # prints "Hello!"
Procedures with Parameters
proc addition(a: int, b: int): int =
  a + b

echo addition(20, 30) # returns 50
Using result
proc double(x: int): int =
  result = x * 2

echo double(5) # returns 10

Useful when building results step-by-step:

proc sumAll(xs: seq[int]): int =
  for n in xs:
    result += n

echo sumAll(@[1,1,1,1,1]) # returns 5
Default Parameters
proc welcome(name = "stranger") =
  echo "Hi, ", name

welcome("Sophie") # prints "Hi, Sophie"
welcome()         # uses default, prints "Hi, stranger"
Procedures returning multiple values
proc divmod(a, b: int): (int, int) =
  (a div b, a mod b)

let (q, r) = divmod(10, 3)
echo q, " ", r   # 3 1
Anonymous Procedures (Lambdas)
let square = proc(x: int): int = x * x
echo square(5) # 25
Procedures within Procedures
proc outer() =
  var count = 0

  proc inner() =
    inc(count)
    echo count

  inner()
  inner()

outer()   # prints 1 then 2
Overloading
proc show(x: int) = echo "int: ", x
proc show(x: string) = echo "string: ", x

show(10)
show("hi")
Discardable Procedure Returns
proc doSomething(): int {.discardable.} =
  123

doSomething()      # allowed now

#Object-Oriented Programming

Ref Objects and Inheritance
type
  Animal = ref object of RootObj
    name: string

  Dog = ref object of Animal
    breed: string

method speak(a: Animal) {.base.} =
  echo a.name, " makes a sound."

method speak(d: Dog) =
  echo d.name, " barks!"

var
  a: Animal = Animal(name: "Creature")
  d: Animal = Dog(name: "Fido", breed: "Mutt")  # Dog upcasted to Animal

speak(a)  # Creature makes a sound.
speak(d)  # Fido barks!

Use ref object of RootObj + method when you need runtime polymorphism.

Procs as Methods
type
  Counter = ref object
    value: int

proc inc(c: var Counter) =
  inc c.value

var c = Counter(value: 0)
inc(c)
echo c.value  # 1
Constructor Procs
type
  Dog = ref object
    name: string
    age: int

proc newDog(name: string; age: int): Dog =
  Dog(name: name, age: age)

let d = newDog("Fido", 3)
echo d.name, " is ", d.age, " years old"
Type tests and Downcasting
type
  Animal = ref object of RootObj
    name: string

  Dog = ref object of Animal
    breed: string

proc newDog(name, breed: string): Dog =
  Dog(name: name, breed: breed)

var a: Animal = newDog("Fido", "mutt")

if a of Dog:                       # runtime type check
  let d = Dog(a)                   # downcast
  echo d.name, " is a ", d.breed

x of Type checks the dynamic type; Type(x) downcasts (unsafe if you lie).

#Imports and Modules

Basic Imports
import std/math

echo sqrt(9.0) # 3.0

See also: Standard Library

Importing Multiple Modules
import std/[strutils, sequtils]

echo "hi".toUpperAscii()    # "HI"
echo @[1,2,3].mapIt(it * 2) # @[2, 4, 6]
Importing Specific Modules
from std/strutils import toLowerAscii

echo toLowerAscii("ABC")  # "abc"
Renaming Modules
import std/random as rng

rng.randomize()

echo rng.rand(1..10) # anywhere from 1 to 10

Don't forget to use randomize() if you're using the std/random library, or else you won't have randomness.

Creating Modules
# utils.nim
proc greet*(name: string) =
  echo "Hello, ", name

(The asterisk means "export this procedure from the module".)


# main.nim
import utils

greet("John") # prints "Hello, John"
`when isMainModule`
proc run() =
  echo "Running..."

when isMainModule:
  run()  # Only runs when this file is the program entry point

Code inside when isMainModule: is skipped when the file is imported.

Re-exporting
# utils.nim
import std/strutils
export strutils    # re-export everything from strutils

Now main.nim can use toUpperAscii directly, through utils.

# main.nim
import utils

echo "hi".toUpperAscii()
Prelude Module
import std/prelude
include std/prelude
  # same as:
  # import std/[os, strutils, times, parseutils, hashes, tables, sets, sequtils, parseopt, strformat]
let x = 1
assert "foo $# $#" % [$x, "bar"] == "foo 1 bar"
assert toSeq(1..3) == @[1, 2, 3]
when not defined(js) or defined(nodejs):
  assert getCurrentDir().len > 0
  assert ($now()).startsWith "20"

#Error Handling

Try - Except - Finally
import std/strutils

try:
  let x = parseInt("42a")         # invalid integer
  echo x
except ValueError as e:
  echo "Value error: ", e.msg     # catch conversion error
except IOError:
  echo "I/O error!"
finally:
  echo "This always runs"
Raising Exceptions
type
  MyError* = object of Exception

proc loadData(name: string) =
  if name == "":
    raise newException(MyError, "No name provided")
  # ... else proceed

loadData("")  # raises MyError
`defer` for Cleanup
proc processFile(path: string) =
  var f = open(path, fmRead)
  defer:
    close(f)
  # work with f …
Try as Exception
import std/strutils

let result = try: parseInt("bad")
             except ValueError: -1

echo result  # prints -1
Exception Tracking with raises
proc riskyOperation() {.raises: [IOError].} =
  # this proc may raise IOError
  raise newException(IOError, "fail")

# A proc with {.raises: []} must not raise any catchable exception.

#Enums

Basic Usage
type
  Direction = enum
    north, east, south, west

var d = north

if d == north:
  echo "Going up!"
Enums and `case`
# with the same Direction enum:

var d = north

case d:
  of north: echo "N"
  of south: echo "S"
  of east:  echo "E"
  of west:  echo "W"
Enum as an Ordinal
# with the same Direction enum:
echo ord(north)   # 0
echo succ(north)  # east
echo pred(south)  # east

#Iterators

Basic Iterator
iterator countUp(a, b: int): int =
  var i = a
  while i <= b:
    yield i      # `yield` produces a value for the `for` loop
    inc i

for n in countUp(1, 5):
  echo n
# 1 2 3 4 5
Common Built-In Iterators
for i in countup(1, 3):
  echo i               # 1 2 3

for i in countdown(3, 1):
  echo i               # 3 2 1
Defining your own Iterator
iterator evensUpTo(n: int): int =
  var x = 0
  while x <= n:
    yield x
    x += 2

for e in evensUpTo(10):
  echo e        # 0 2 4 6 8 10

#Files & IO

Check Paths and Existence
import std/os

if fileExists("data.txt"):
  echo "File exists!"

if dirExists("configs"):
  echo "Directory exists!"

echo getCurrentDir()
echo absolutePath("data.txt")
Read / Write Whole File
# Write whole file
writeFile("out.txt", "Hello Nim!\n")

# Read whole file
let text = readFile("out.txt")
echo text
Manual Open/Close with `defer`
import std/syncio

proc writeLog() =
  var f = open("log.txt", fmWrite)
  defer: f.close()
  f.writeLine("entry 1")
  f.writeLine("entry 2")

when isMainModule:
  writeLog()
Read a File Line-By-Line
for line in lines("data.txt"):
  echo line

#Generics

Generic Types and Procedures
type
  Box[T] = object
    value: T

proc wrap[T](x: T): Box[T] =
  Box[T](value: x)

let a = wrap(10)        # Box[int]
let b = wrap("hello")   # Box[string]

echo a.value            # 10
echo b.value            # hello

#Templates and Macros

Templates
# Template = macro-like, expanded at compile time
template times2(x: untyped): untyped = (x) * 2
echo times2(21)  # 42
Macros
import std/macros

macro dbg(expr: untyped): untyped =
  # prints both the expression and its value
  result = quote do:
    echo astToStr(`expr`), " = ", `expr`

let x = 10
dbg(x * 2)
# prints: x * 2 = 20