git clone -b devel git://github.com/nim-lang/Nim.git cd Nim git clone -b devel --depth 1 git://github.com/nim-lang/csources cd csources && sh build.sh cd .. bin/nim c koch ./koch boot -d:release
| Website | http://nim-lang.org |
| Mailing list | http://www.freelists.org/list/nim-dev |
| Forum | http://forum.nim-lang.org |
| Github | https://github.com/Araq/Nim |
| IRC | irc.freenode.net/nim |
echo "hello world!"
echo "hello world!"
nim c -r hello.nim
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | proc decimalToRoman*(number: range[1..3_999]): string = ## Converts a number to a Roman numeral. const romanComposites = { "M": 1000, "CM": 900, "D": 500, "CD": 400, "C": 100, "XC": 90, "L": 50, "XL": 40, "X": 10, "IX": 9, "V": 5, "IV": 4, "I": 1} result = "" var decVal = number.int for key, val in items(romanComposites): while decVal >= val: decVal -= val result.add(key) echo decimalToRoman(1009) # MIX |
Function application is f(), f(a), f(a, b).
Function application is f(), f(a), f(a, b).
And here is the sugar:
| Sugar | Meaning | Example |
|---|---|---|
| f a | f(a) | spawn log("some message") |
| a.f() | f(a) | db.fetchRow() |
| a.f | f(a) | mystring.len |
| f a, b | f(a, b) | echo "hello ", "world" |
| a.f(b) | f(a, b) | myarray.map(f) |
| a.f b | f(a, b) | db.fetchRow 1 |
| f"\n" | f(r"\n") | re"\b[a-z*]\b" |
Function application is f(), f(a), f(a, b).
And here is the sugar:
| Sugar | Meaning | Example |
|---|---|---|
| f a | f(a) | spawn log("some message") |
| a.f() | f(a) | db.fetchRow() |
| a.f | f(a) | mystring.len |
| f a, b | f(a, b) | echo "hello ", "world" |
| a.f(b) | f(a, b) | myarray.map(f) |
| a.f b | f(a, b) | db.fetchRow 1 |
| f"\n" | f(r"\n") | re"\b[a-z*]\b" |
BUT: f does not mean f(); myarray.map(f) passes f to map
`@`(x, y) x.`@`(y) `@`(x) x.`@`() x.`@`
proc `++`(x: var int; y: int = 1; z: int = 0) = x = x + y + z var g = 70 ++g g ++ 7 g.`++`(10, 20) echo g # writes 108
1 2 3 4 5 6 7 | when defined(posix): proc getCreationTime(file: string): Time = var res: Stat if stat(file, res) < 0'i32: let error = osLastError() raiseOSError(error) return res.st_ctime |
Statements require indentation:
# no indentation needed for single assignment statement: if x: x = false # indentation needed for nested if statement: if x: if y: y = false else: y = true # indentation needed, because two statements follow the condition: if x: x = false y = false
Expressions do not:
if thisIsaLongCondition() and thisIsAnotherLongCondition(1, 2, 3, 4): x = true
tuple
1 2 3 4 5 6 7 8 9 | proc `+-`(x, y: int): (int, int) = (x - y, x + y) # alternatively proc `+-`(x, y: int): tuple[lowerBound, upperBound: int] = (x - y, x + y) let tup = 100 +- 10 echo tup[0], " ", tup.upperBound # tuple unpacking let (lower, _) = 100 +- 10 |
object
1 2 3 4 5 6 7 8 9 | type Rect = object x, y, w, h: int # construction: let r = Rect(x: 12, y: 22, w: 40, h: 80) # field access: echo r.x, " ", r.y |
enums & sets
1 2 3 4 5 6 7 8 9 | type SandboxFlag* = enum ## what the interpreter should allow allowCast, ## allow unsafe language feature: 'cast' allowFFI, ## allow the FFI allowInfiniteLoops ## allow endless loops SandboxFlags* = set[SandboxFlag] proc runNimCode(code: string; flags: SandboxFlags = {allowCast, allowFFI}) = ... |
1 2 3 4 5 6 7 | #define allowCast (1 << 0) #define allowFFI (1 << 1) #define allowInfiniteLoops (1 << 1) void runNimCode(char* code, unsigned int flags = allowCast|allowFFI); runNimCode("4+5", 700); |
ref and ptr
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # Model a regular expression type RegexKind = enum ## the regex AST's kind reChar, ## character node "c" reCClass, ## character class node "[a-z]" reStar, ## star node "r*" rePlus, ## plus node "r+" reOpt, ## option node "r?" reCat, ## concatenation node "ab" reAlt, ## alternatives node "a|b" reWordBoundary ## "\b" RegExpr = ref object case kind: RegexKind of reWordBoundary: discard of reChar: c: char of reCClass: cc: set[char] of reStar, rePlus, reOpt: child0: RegExpr of reCat, reAlt: child1, child2: RegExpr |
1 2 3 4 5 6 7 8 9 | proc `==`(a, b: RegExpr): bool = if a.kind == b.kind: case a.kind of reWordBoundary: result = true of reChar: result = a.c == b.c of reCClass: result = a.cc == b.cc of reStar, rePlus, reOpt: result = `==`(a.child0, b.child0) of reCat, reAlt: result = `==`(a.child1, b.child1) and `==`(a.child2, b.child2) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | type HashTable[K, V] = object data: seq[(K, V)] proc hash[K](k: K): int = 0 proc `[]`*[K, V](x: HashTable[K, V]; k: K): V = result = x.data[hash(k)][1] proc `[]=`*[K, V](x: var HashTable[K, V]; k: K, v: V) = x.data[hash(k)][1] = v proc initHashTable[K, V](): HashTable[K, V] = result.data = @[] var tab = initHashTable[string, string]() tab["key"] = "abc" # calls '[]=' accessor echo tab["key"] # calls '[]' accessor |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | type HashTable[K, V] = object data: seq[(K, V)] proc hash[K](k: K): int = 0 proc `[]`*[K, V](x: HashTable[K, V]; k: K): V = result = x.data[hash(k)][1] proc `[]=`*[K, V](x: var HashTable[K, V]; k: K, v: V) = x.data[hash(k)][1] = v proc initHashTable[K, V](): HashTable[K, V] = result.data = @[] var tab = initHashTable[string, string]() tab["key"] = "abc" # calls '[]=' accessor echo tab["key"] # calls '[]' accessor # ouch: tab["key"].add "xyz" |
1 2 3 4 5 6 7 8 9 | proc `[]`*[Key, Value](x: var HashTable[Key, Value]; k: Key): var Value = result = x.data[hash(key)] var tab = initHashTable[string, string]() # compiles :-) tab["key"].add "xyz" |
1 2 3 4 5 6 7 8 9 10 | # Taken from system.nim const taintMode = compileOption("taintmode") when taintMode: type TaintedString* = distinct string proc len*(s: TaintedString): int {.borrow.} else: type TaintedString* = string proc readLine*(f: File): TaintedString {.tags: [ReadIOEffect], benign.} |
1 2 3 | # taintmode_ex echo readLine(stdin) |
nim c -r --taintMode:on taintmode_ex
1 2 3 | # taintmode_ex echo readLine(stdin).string |
nim c -r --taintMode:on taintmode_ex
1 2 3 4 5 | # taintmode_ex proc `$`(x: TaintedString): string {.borrow.} # but: defeats the purpose echo readLine(stdin) |
nim c -r --taintMode:on taintmode_ex
1 2 3 4 5 | # Module A var global*: string = "A.global" proc p*(x: string) = echo "exported ", x |
1 2 3 4 | # Module B import A echo p(global) |
1 2 3 4 5 | # Module A var global*: string = "A.global" proc p*(x: string) = echo "exported ", x |
1 2 3 4 | # Module B from A import p echo p(A.global) |
1 2 3 4 5 | # Module A var global*: string = "A.global" proc p*(x: string) = echo "exported ", x |
1 2 3 4 | # Module B import A except global echo p(A.global) |
1 2 3 4 5 6 7 8 | iterator `..<`(a, b: int): int = var i = a while i < b: yield i i += 1 for i in 0..<10: echo i+1, "-th iteration" |
1 2 | for x in [1, 2, 3]: echo x |
1 2 | for x in [1, 2, 3]: echo x |
Rewritten to:
1 2 | for x in items([1, 2, 3]): echo x |
1 2 3 4 5 | iterator items*[IX, T](a: array[IX, T]): T {.inline.} = var i = low(IX) while i <= high(IX): yield a[i] i += 1 |
1 2 | for x in [1, 2, 3]: x = 0 # doesn't compile |
1 2 3 | var a = [1, 2, 3] for x in a: x = 0 # doesn't compile |
1 2 3 4 5 6 7 8 9 10 11 | iterator mitems*[IX, T](a: var array[IX, T]): var T {.inline.} = var i = low(IX) if i <= high(IX): while true: yield a[i] if i >= high(IX): break i += 1 var a = [1, 2, 3] for x in mitems(a): x = 0 # compiles |
1 2 3 4 5 6 7 | import tables, strutils proc countWords(filename: string): CountTableRef[string] = ## Counts all the words in the file. result = newCountTable[string]() for word in readFile(filename).split: result.inc word |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # # const files = ["data1.txt", "data2.txt", "data3.txt", "data4.txt"] proc main() = var tab = newCountTable[string]() for f in files: let tab2 = countWords(f) tab.merge(tab2) tab.sort() echo tab.largest main() |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import threadpool const files = ["data1.txt", "data2.txt", "data3.txt", "data4.txt"] proc main() = var tab = newCountTable[string]() var results: array[files.len, FlowVar[CountTableRef[string]]] for i, f in files: results[i] = spawn countWords(f) for i in 0..high(results): tab.merge( ^results[i] ) tab.sort() echo tab.largest main() |