Nim Introduction

by "Blag" - Senior Developer Evangelist

Return to Geeky Thursday

What is Nim?


Concise, fast programming language that compiles to C, C++ and JavaScript.


High-performance garbage-collected language.


Produces dependency-free binaries.


Binds to C, C++ and Objective C libraries.

How to install Nim?


On Linux run this on the terminal


sudo apt-get install -y nim


On a Mac do brew install nim.


On Windows, follow this link


Basically install and setup some paths...


Who uses Nim?


Nim is still a young language...but there are companies using it in production


  • Unicredit - Largest bank in Italy
  • OnSetGames - Creators of Reel Valley
  • MakeSpace - On-demand storage service

Starting out...


Nim doesn't come with a REPL...


We must compile before run...


nim c file_name.nim


./file_name

Package Management


Nim's package manager is called "Nimble"


It should be installed already (use nimble -v)...if not check here


				
nimble install <name_of_package>


nimble install <url_of_package>
                

Basic Concepts


Printing on the screen is easy...

And only one line comments are allowed...

				
echo("This is Nim!")


#This is a Nim comment 
				

Variables can be mutable or immutable...


				
let myLetVar:int = 5

#Immutable...


var myVarVar:int = 10

#Mutable
				

Arrays are easy...


				
let numArray = [1, 2, 3]

for num in numArray:

  echo(num)

#1

#2

#3


#Arrays are size fixed...they cannot change...
				

Arrays are easy...


				
var names: array[0..2, string]


names[0] = "Nim"

names[1] = "Crystal"

names[2] = "Elixir"


for name in names:

  echo(name)
  
  
# Nim

# Crystal

# Elixir  
				

Multi-dimensional arrays are easy too...


				
var names: array[0..2, array[0..2,string]]


names[0][0] = "Nim"

names[0][1] = "Crystal"

names[0][2] = "Elixir"

names[1][0] = "Elm"


echo(names[0][1])

echo(names[1][0])


# Crystal

# Elm
				

We can iterate on Arrays and Hashes


				
let langs = ["Spanish","English","German"]


for lang in langs:

  echo(lang)


#Spanish

#English

#German
				
				
import tables


let langs = toTable[string, string](

  {

  "Spanish": "Peru",

  "English": "US",

  "German": "Germany"

  }

)


for key, value in langs:

  echo(key, " is spoken in ", value)


#Spanish is spoken in Peru

#English is spoken in US

#German is spoken in Germany
				

Functions


Functions always return the last value

				
proc concat(a, b: string): string = 
  
  a & " " & b


  
let message = concat("Hello", "Nim")


echo(message) #Hello Nim
				

Although sometimes is needed...


Objects


In Nim, we can create objects, to help us define custom types


				
type


  Person = object

    name: string

    age: int


var person = Person(name: "Blag", age: 40)

echo(person)

#(name: Blag, age: 40)
  		
				
type

  PersonObj = object

    name: string

    age: int

  PersonRef = ref PersonObj


proc setName(person: PersonRef, name: string) =

  person.name = name


var newperson = PersonRef(name: "Blag", age: 40)


setName(newperson, "Alvaro")


echo(newperson.name) # Alvaro
				

Fibonacci List


Finally...we're going to make our first application...


So grab your favorite text editor and get ready...


Name your file "fibonacci.nim"


				
import parseutils



proc fib(num, a, b: int): string = 

  result = ""

  if a > 0 and num > 1:

    result = result & " " & $(a + b) & 
    
             fib(num - 1, a + b, a)

  elif a == 0:

    result = $a & " " & $b & " " & $(a + b) & 
    
             fib(num - 1, a + b, b) 
				
				
stdout.write("Enter a number: ")

let num = stdin.readLine()

var iNum = 0

discard parseInt(num, iNum)

echo(fib(iNum, 0, 1))
				

Open the Terminal and go to your source code folder...


nim c "Name_of_File.nim"

./"Name_of_File"


When we run it we're going to see...


Making an LED Number App


This is one of my favorite codes of all time...


Name your file "LED_Numbers.nim"


				
import tables, parseutils


let leds = toTable[int, array[0..2,string]](

  {

  0: [" _  ","| | ","|_| "],

  1: ["  ","| ","| "],

  2: [" _  "," _| ","|_  "],

  3: ["_  ","_| ","_| "],

  4: ["    ","|_| ","  | "],

  5: [" _  ","|_  "," _| "],

  6: [" _  ","|_  ","|_| "],

  7: ["_   "," |  "," |  "],

  8: [" _  ","|_| ","|_| "],

  9: [" _  ","|_| "," _| "]

  })
				
				
stdout.write("Enter a number: ")

let num = stdin.readLine()



for i in countup(0, 2):

  for item in num:

    var iNum = 0

    discard parseInt($item, iNum) 

    stdout.write(leds[iNum][i])

  echo("")
				

When we run it we're going to see...


Random Names


This App will generate 100,000 random names using two 16 elements arrays


We will measure the runtime


Name your file "Random_Names.nim"


				
import random, times


let start = epochTime()


randomize()


let names = ["Anne","Gigi","Blag","Juergen","Marek",

             "Ingo","Lars","Julia","Danielle","Rocky",
             
             "Julien","Uwe","Myles","Mike","Steven",
             
             "Fanny"]



let last_names = ["Hardy","Read","Tejada","Schmerder",

                  "Kowalkiewicz","Sauerzapf","Karg",

                  "Satsuta","Keene","Ongkowidjojo",

                  "Vayssiere","Kylau","Fenlon",

                  "Flynn","Taylor","Tan"]
				
				
var full_names: array[0..99999, string]



for i in countup(0, 99999):

  full_names[i] = names[random(16)] & " " & 
  
                  last_names[random(16)]



let finish = epochTime() - start

echo(finish)
			

When we run it we're going to see...

How this behaves in Python?

And what about Go?

Decimal to Romans


This App will create a Roman Numeral based on a decimal number


This will include some nice commands...


Name your file "Decimal_to_Roman.nim"


				
import tables, parseutils



let roman_table = toOrderedTable[int, string](

  {

  1000: "M",

   900: "CM",

   500: "D",

   400: "CD",

   100: "C",

    90: "XC",

    50: "L",

    40: "XL",

    10: "X",

     9: "IX",

     5: "V",

     4: "IV",

     1: "I"

  })
			
				
proc roman_number(number: var int): string =

  var result = ""

  while number > 0:

    for key, value in roman_table:

      if number >= key:

        result &= value

        number -= key

        break

  return result
			
				
stdout.write("Enter a number: ")

let num = stdin.readLine()

var number = 0

discard parseInt($num, number)

echo(roman_number(number))
				

When we run it we're going to see...


Count Letters


In this example we're going to read a file and count how many time a letter appears...


Call your file "count_letters.nim" (all in lowercase).


Create a file called "readme.txt" with the following text...


"This is a text file that we're going to read using Nim"


				
import tables

var file: File

var counter = initCountTable[char]()

if open(file, "readme.txt"):

  try:

    let line = readLine(file)

    for item in line:

      counter.inc(item)

  except IOError:

    echo("Not found!")

  finally:

    close(file)

for key, value in counter:

  echo(key, " => ", value)
				

When we run it we're going to see...


Concurrency


Create processes in Nim is pretty easy.

A single thread can use the power of a CPU core.

We use a Pool Thread to manage threads in the best way

Name your file "concurrent.nim"


				
import threadpool, os, times


proc process(n:string) =

  sleep(3000)

  echo("Process ", n)



proc spawn_process(n:int) =

  spawn process($n)



proc run_no_concurrent() =

  for i in countup(0, 4):

    process($i)

  process("Another process")
				
				
proc run_concurrent() =

  for i in countup(0, 4):

    spawn_process(i)

  process("Another process")



echo("Non Concurrent")

let start = epochTime()

run_no_concurrent()

let finish = epochTime() - start

echo(finish)

echo("\n")
				
				
echo("Concurrent")

let startc = epochTime()

run_concurrent()

let finishc = epochTime() - startc

echo(finishc)
				

Before compiling, we need to activate threads...

Create a file called "concurrent.nims"

				
--threads:on
				

When we run it we're going to see...

The concurrent version took about 1/3 of the Non Concurrent time...

Going beyond...


Nim is still young but it already has one really nice library...


Jester - Web Framework


Jester is a sinatra-like web framework.


It's very similar to Ruby's Sinatra


Jester provides a DSL for quickly creating web applications in Nim


Create a new folder and call it "Fibonacci"...

On the terminal, go inside the folder and type

nimble init


Answer the questions and for the default ones simply press "Enter"...

Edit the generated "Fibonacci.nimble" file like this...


Create a new file and call it "fibonacci.nim" with the following code...

				
import asyncdispatch, parseutils 

import jester

import controller, views/index, views/getfibo


routes:

  get "/":

    resp renderMain(renderIndex())



  post "/getfibo":

    var iNum = 0

    discard parseInt(@"num", iNum)

    var result = fib(iNum, 0, 1)

    resp renderMain(renderFibo(result))


runForever()

				

Now, create a new file and call it "controller.nim" with the following code...

				
proc fib*(num, a, b: int): string = 

  result = ""

  if a > 0 and num > 1:

    result = result & " " & $(a + b) & 
    
             fib(num - 1, a + b, a)

  elif a == 0:

    result = $a & " " & $b & " " & 
    
             $(a + b) & fib(num - 1, a + b, b)
				

Create a new folder called "Views" and one file called "index.nim"

				
#? stdtmpl(subsChar = '$', metaChar = '#')

#import xmltree

#

#proc `$!`(text: string): string = escape(text)

#end proc

#

#proc renderMain*(body: string): string =

#  result = ""

<!DOCTYPE html>

<html>

  <head>

    <title>Fibonacci List</title>

  </head>
				
				
  <body>

    ${body}

  </body>



</html>

#end proc

#  

#proc renderIndex*(): string =

#  result = ""

<div id="fibo">

  <h2>Fibonacci List</h2>

  <span class="small">Enter a number</span>

  <form action="getfibo" method="post">

    <input type="text" name="num">
				
				
    <input type="text" name="num">

    <input type="submit" value="Send">

  </form>

</div>

#end proc
				

To finish, create a new file inside the "Views" folder and call it "getfibo.nim"

				
#? stdtmpl(subsChar = '$', metaChar = '#')

#import xmltree

#

#proc `$!`(text: string): string = escape(text)

#end proc

#

#proc renderFibo*(num: string): string =

#  result = ""

<div id="result">

  <h1>${num}</h1>

  <a href="/">Go back...</a>

</div>

#end proc
				

To run we simply need to do


nimble c -r fibonacci.nim


And then go to http://localhost:5000 on the browser...


That's it for now


Nim is an awesome and impressive language


So keep an eye...it will become better and better -;)


Contact Information


Blag --> blag@blagarts.com

@Blag on Twitter

Go back home...