Abhishek Kapatkar
Engineer @ Netflix
For Python Programmers
Twitter/Github: @cabhishek
San Francisco
Nim is an incredibly fast systems and applications programming language that is expressive, extensible and fun to use.
echo "hello, 世界"
Features | Python | Nim |
---|---|---|
Execution Model | Interpreted | Compiled |
Memory Management | Automatic | Automatic or Manual |
Types | Dynamic | Static |
Generics | Duck Typing | Yes |
Object Oriented | Yes | Minimal |
Closures | Yes | Yes |
Function overload | No | Yes |
Distribution | Requires CPython | Binary |
Multi Threaded | No | Yes |
Performance | Depends? | Comparable to C/C++ |
proc search(a: seq[int], key: int): bool =
# type inferred
var
low = 0
high = len(a) - 1
while low <= high:
let mid: int = (low + high) div 2 # integer division
if key < a[mid]:
high = mid - 1
elif key > a[mid]:
low = mid + 1
else:
return true
return false
echo search(@[2,3,4,5,6,7,8], 5) # true
Instead of writing
foo(bar(a))
a.bar().foo()
It is possible to write
echo @[1,2,3,4,5].map(a => a * 2).filter(a => a > 2).foldr(a + b) # 28
echo evens(divide(multiply(values, 10), 3))
vs
echo values.multiply(10).divide(3).evens
import strutils, strformat
type
Person = object
name: string
age: int
proc speak (p: Person) =
echo fmt"My name is {p.name} and I am {p.age} years old."
let person = Person(name: "jim", age: 30)
person.speak() # My name is jim and I am 30 years old.
type
Status = enum
open, closed, pending
Account = object
status: Status
balance: float
name: string
proc deposit(account: var Account, amount: float) =
account.balance += amount
var account: Account = (
status: Status.open,
balance: 150.2,
name: "my savings"
)
account.deposit(20)
echo account.balance # 170.2
type Point = tuple[x, y: int]
proc `+`(a, b: Point): Point =
(a.x + b.x, a.y + b.y)
let
p1 = (x: -1, y: 4)
p2 = (x: 5, y: -2)
p3 = p1 + p2
echo p3 # (x: 4, y: 2)
iterator `->`(from, to: int): int =
var i = from
while i < to:
yield i
inc(i)
for x in 0->5: echo x
type Point = tuple[x, y: int]
proc `+`(a, b: Point): Point =
(a.x + b.x, a.y + b.y)
let
p1 = (x: -1, y: 4)
p2 = (x: 5, y: -2)
p3 = `+`(p1, p2)
echo p3 # (x: 4, y: 2)
proc range(start, till: int, step: int = 1): iterator(): int =
return iterator(): int {.closure.} =
var x = start
while x < till:
yield x
x += step
proc print(iter: iterator(): int) =
for item in iter(): echo item
print(range(1, 10, step=2)) # 1 3 5 7 9
import sequtils
proc double(x: int): int = x*x
let square = double
echo map(@[1,2,3], square) #1, 4, 9
import seqUtils
echo map(
@[1,2,4,5],
proc(x: int): int =
let y = x * 2
y + 2
)
# @[4, 6, 10, 12]
json
httpclient (async + sync)
unittest
os - Basic operating system facilities
strutils - Various string utility routines
sequtils - Operations for the built-in seq type which are inspired by functional programming languages
tables - Hashtable/Dictionary
algorithm & math
...
Metaprogramming is a programming technique in which computer programs have the ability to treat programs as their data. It means that a program can be designed to read, generate, analyse or transform other programs, and even modify itself while running
- Wikipedia
proc max[T](a, b: T): T =
if a < b:
return b
else:
return a
echo max(1, 2) # 2, inferred type is max[int]
echo max[float](11.9, 8.0) # 11.9, explicit type
echo max("hello", "world") # world
echo max("one", 1) #Error: type mismatch
type
Node[T] = object
next: Node[T]
data: T
proc newNode[T](data: T): Node[T] =
Node[T](data: data)
let
n1 = newNode(12)
n2 = newNode("New York")
proc max[T: int | float](a, b: T): T =
if a < b:
return b
else:
return a
echo max("hello", "world") # type mismatch error
Allows simple substitution mechanism operating on Nim's AST
To invoke a template, call it like a procedure
Templates are declarative
echo mul(2, 3)
echo 2 * 3
At compile time its re-written to
template mul(x, y: int): int = x * y
import macros
macro mul(x, y: int): typed =
expectKind(x, nnkIntLit)
expectKind(y, nnkIntLit)
let stmtList = newNimNode(nnkStmtList)
stmtList.add(
newCall(
newIdentNode("echo"),
newStrLitNode("Result is: "),
infix(x, "*", y)
)
)
return stmtList
mul(2, 2) # Result is: 4
import marcos
dumpTree:
echo("Result is: ", 2*2)
# StmtList
# Call
# Ident !"echo"
# StrLit Result is:
# Infix
# Ident !"*"
# IntLit 2
# IntLit 2
GC safety, isolated heaps & sharing memory is restricted
threads and threadpool module
import threadpool, locks
var lock: Lock
initLock(lock)
var counter {.guard: lock.} = 0
proc increment(x: int) =
for i in 0.. <x:
withLock lock:
inc(counter)
spawn increment(10_000)
spawn increment(10_000)
sync()
echo counter # 20000
var data = "Hello World"
proc showData() {.thread.} =
echo data
var thread: Thread
createThread(thread, showData)
joinThread(thread)
# 'showData' is not GC-safe as it accesses 'data'
# which is a global using GC'ed memory [GcUnsafe2]
import os, locks
var
threads: array[0..4, Thread[int]]
channel: Channel[string]
counter: int
lock: Lock
proc worker(interval: int) {.thread.} =
while true:
let data = channel.tryRecv()
if data.dataAvailable:
echo "> Got msg: " & data.msg
echo "> Doing work"
acquire(lock)
counter += 1 #shared data, actual work is to increment
release(lock)
sleep(interval) # long running work
echo "> Done with work"
break
else:
# slow the channel poll
sleep(interval)
echo "> Waiting for work"
when isMainModule:
initLock(lock)
channel.open()
defer: channel.close()
for i in 0..high(threads):
createThread(threads[i], worker, 200)
for i in 0..high(threads):
sleep(50) # delay to start work
channel.send("Start work") # signal
joinThreads(threads) # wait for completion
echo "Counter value: " & $counter #5
Supports C/C++ and Javascript backends
https://nim-lang.org/docs/backends.html
Cross compilation
https://nim-lang.org/docs/nimc.html#cross-compilation
Nim Installer
https://nim-lang.org/docs/niminst.html
Self hosted
No GIL
FFI (Foreign function interface)
async/await
Default function parameters
Variable length arguments
Named function arguments
Multiple return values [via tuples]
Case/If statements as expression
Package manager
Docs generator
....
Web services / API's
Command line applications
Compilers
Scientific computing
Games
Automation scripts
UI applications
Python C extensions
And more...
Arraymancer: A fast, ergonomic and portable tensor library with a deep learning focus
ao: Physically based ray tracer in Nim
Jester: A sinatra-like web framework
Karax: Single page JS applications
Reel valley: Game in JS. Details here
Spry: Programing language
Nim pymod: Call Nim from Python
Razcal: Build cross platform desktop app with Lua, MoonScript, and Layout Language
...
Smaller ecosystem
Occasional compiler bugs
https://nim-lang.org
Installation via ChooseNim
Nim in Action [Book]
Tutorials
Language manual
Code examples:
Interactive playground
Unofficial Nim blog
IRC: #nim on Freenode
Gitter: nim-lang/nim
Twitter: @nim_lang
Language goals
Efficiency
Expressiveness
Elegance
Key takeaway points
Incredibly fast, extensible & fun
Python look & feel
Zero dependency binary distribution
Comprehensive Std library
@cabhishek
By Abhishek Kapatkar
Intro to Nim language for python developers.