Procs

Procedures in Nim are declared using proc and require that their parameter and return types be annotated. After the types and parameters, an = is used to denote the start of the function body. Another thing to note is that procedures have uniform function call syntax, which means that they can called as both foo(a, b) or a.foo(b).

proc fibonacci(n: int): int =
  if n < 2:
    result = n
  else:
    result = fibonacci(n - 1) + (n - 2).fibonacci

Exporting symbols

Encapsulation is also supported, not by conventions such as perpending the name with underscores but by annotating a procedure with *, which exports it and makes it available for use by modules.

# module1:
proc foo*(): int = 2
proc bar(): int = 3

# module2:
echo foo()  # Valid
echo bar()  # will not compile

Side effect analyses

Nim provides support for functional programming and so includes the {.noSideEffect.} pragma, which statically ensures there are no side effects.

proc sum(x, y: int): int {. noSideEffect .} =
  x + y

proc minus(x, y: int): int {. noSideEffect .} =
  echo x  # error: 'minus' can have side effects
  x - y

Operators

To create an operator, the symbols that are to be used must be encased inside `s to signify they are operators.

proc `$`(a: array[2, array[2, int]]): string =
  result = ""
  for v in a:
    for vx in v:
      result.add($vx & ", ")
    result.add("\n")

echo([[1, 2], [3, 4]])  # See varargs for
                        # how echo works

proc `^&*^@%`(a, b: string): string =
  ## A confusingly named useless operator
  result = a[0] & b[high(b)]

assert("foo" ^&*^@% "bar" == "fr")

Generic Functions

Generic functions are like C++’s templates and allow for the same statically checked duck-typing semantics as templates.

# Not really good idea for obvious reasons
let zero = ""
proc `+`(a, b: string): string =
  a & b

proc `*`[T](a: T, b: int): T =
  result = zero
  for i in 0..b:
    result = result + a  # calls `+` from line 3

assert("a" * 10 == "aaaaaaaaaaa")