├── 1_intro.html
├── 1_intro.rst
├── 2_meta.html
├── 2_meta.rst
├── 3_effects.html
├── 3_effects.rst
├── 4_cppinterop.html
├── 4_cppinterop.rst
├── build.nim
├── busyteam2.png
├── livedemo
├── codegendecl.nim
├── coverage.nim
├── coverage2.nim
├── demo.html
├── demo.nim
├── file.c2nim
├── file.h
├── file.nim
└── options.c2nim
├── logo2.png
├── nimdoc.cfg
├── overview.rst
└── slidy2
├── Overview.html
├── Overview.xhtml
├── blank.html
├── graphics
├── bullet-fold-dim.gif
├── bullet-fold-dim.png
├── bullet-fold.gif
├── bullet-fold.png
├── bullet-nofold-dim.gif
├── bullet-nofold-dim.png
├── bullet-nofold.gif
├── bullet-nofold.png
├── bullet-unfold-dim.gif
├── bullet-unfold-dim.png
├── bullet-unfold.gif
├── bullet-unfold.png
├── bullet.gif
├── bullet.png
├── example.png
├── example.svg
├── face1.gif
├── face2.gif
├── face3.gif
├── face4.gif
├── fold-bright.gif
├── fold-dim.bmp
├── fold-dim.gif
├── fold.bmp
├── fold.gif
├── icon-blue.png
├── keys2.jpg
├── nofold-dim.bmp
├── nofold-dim.gif
├── nofold.bmp
├── unfold-bright.gif
├── unfold-dim.bmp
├── unfold-dim.gif
├── unfold.bmp
├── unfold.gif
├── w3c-logo-blue.gif
├── w3c-logo-blue.svg
├── w3c-logo-slanted.jpg
├── w3c-logo-white.gif
└── w3c-logo-white.svg
├── help
├── .htaccess
├── help.html
├── help.html.ca
├── help.html.de
├── help.html.en
├── help.html.es
├── help.html.fr
├── help.html.hu
├── help.html.nl
├── help.html.pl
├── help.html.pt-br
├── help.html.pt_br
├── help.html.sv
└── help.pt-br.html
├── scripts
├── .htaccess
├── img.srcset.js
└── slidy.js
└── styles
├── .htaccess
├── print.css
├── slidy.css
└── w3c-blue.css
/1_intro.rst:
--------------------------------------------------------------------------------
1 | ============================================================
2 | The ultimate introduction
3 | ============================================================
4 |
5 |
6 | .. raw:: html
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Slides
16 |
17 | git clone https://github.com/Araq/oscon2015
18 |
19 |
20 |
21 | Download
22 |
23 | http://nim-lang.org/download.html
24 |
25 |
26 |
27 | Installation
28 | ============
29 |
30 | ::
31 | git clone -b devel git://github.com/nim-lang/Nim.git
32 | cd Nim
33 | git clone -b devel --depth 1 git://github.com/nim-lang/csources
34 | cd csources && sh build.sh
35 | cd ..
36 | bin/nim c koch
37 | ./koch boot -d:release
38 |
39 |
40 | What is Nim?
41 | ============
42 |
43 | - new **systems** programming language
44 | - compiles to C
45 | - garbage collection + manual memory management
46 | - thread local garbage collection
47 | - design goals: efficient, expressive, elegant
48 |
49 | ..
50 | * Nim compiles to C; C++ and Objective-C are also supported
51 | * there is an experimental JavaScript backend
52 | * it provides a soft realtime GC: you can tell it how long it is allowed to run
53 | * the Nim compiler and **all** of the standard library (including the GC)
54 | are written in Nim
55 | * whole program dead code elimination: stdlib carefully crafted to make use
56 | of it; for instance parsers do not use (runtime) regular expressions ->
57 | re engine not part of the executable
58 | * our infrastructure (IDE, build tools, package manager) is
59 | also completely written in Nim
60 | * infix/indentation based syntax
61 |
62 |
63 | Philosophy
64 | ==========
65 |
66 | * power
67 | * efficiency
68 | * fun
69 |
70 | ..
71 | Talk about what the plans for Nim were
72 |
73 |
74 |
75 | Why Nim?
76 | ========
77 |
78 | - Major influences: Modula 3, Delphi, Ada, C++, Python, Lisp, Oberon.
79 |
80 | - Development started in 2006
81 | - First successful bootstrapping in 2008
82 | - compiler written in Delphi
83 | - converted to Nim via "pas2nim"
84 |
85 |
86 | Uses of Nim
87 | ===========
88 |
89 | - games
90 | - compilers
91 | - operating system development
92 | - scientific computing
93 | - scripting
94 |
95 |
96 | Nim at 3dicc
97 | ============
98 |
99 | .. raw:: html
100 |
101 |
102 |
103 |
104 | URLs
105 | ====
106 |
107 | ============ ================================================
108 | Website http://nim-lang.org
109 | Mailing list http://www.freelists.org/list/nim-dev
110 | Forum http://forum.nim-lang.org
111 | Github https://github.com/Araq/Nim
112 | IRC irc.freenode.net/nim
113 | ============ ================================================
114 |
115 |
116 |
117 | Hello World
118 | ===========
119 |
120 | .. code-block:: nim
121 | echo "hello world!"
122 |
123 |
124 | Hello World
125 | ===========
126 |
127 | .. code-block:: nim
128 | echo "hello world!"
129 |
130 | ::
131 | nim c -r hello.nim
132 |
133 |
134 |
135 | More Code!
136 | ==========
137 |
138 | .. code-block:: nim
139 | :number-lines:
140 |
141 | proc decimalToRoman*(number: range[1..3_999]): string =
142 | ## Converts a number to a Roman numeral.
143 | const romanComposites = {
144 | "M": 1000, "CM": 900,
145 | "D": 500, "CD": 400, "C": 100,
146 | "XC": 90, "L": 50, "XL": 40, "X": 10, "IX": 9,
147 | "V": 5, "IV": 4, "I": 1}
148 | result = ""
149 | var decVal = number.int
150 | for key, val in items(romanComposites):
151 | while decVal >= val:
152 | decVal -= val
153 | result.add(key)
154 |
155 | echo decimalToRoman(1009) # MIX
156 |
157 |
158 | - ``{"M": 1000, "CM": 900}`` sugar for ``[("M", 1000), ("CM", 900)]``
159 | - ``result`` implicitly available
160 |
161 |
162 | Nimble
163 | ======
164 |
165 | - Live demo.
166 |
167 |
168 | Function application
169 | ====================
170 |
171 | Function application is ``f()``, ``f(a)``, ``f(a, b)``.
172 |
173 |
174 | Function application
175 | ====================
176 |
177 | Function application is ``f()``, ``f(a)``, ``f(a, b)``.
178 |
179 | And here is the sugar:
180 |
181 | =========== ================== ===============================
182 | Sugar Meaning Example
183 | =========== ================== ===============================
184 | ``f a`` ``f(a)`` ``spawn log("some message")``
185 | ``a.f()`` ``f(a)`` ``db.fetchRow()``
186 | ``a.f`` ``f(a)`` ``mystring.len``
187 | ``f a, b`` ``f(a, b)`` ``echo "hello ", "world"``
188 | ``a.f(b)`` ``f(a, b)`` ``myarray.map(f)``
189 | ``a.f b`` ``f(a, b)`` ``db.fetchRow 1``
190 | ``f"\n"`` ``f(r"\n")`` ``re"\b[a-z*]\b"``
191 | =========== ================== ===============================
192 |
193 |
194 | Function application
195 | ====================
196 |
197 | Function application is ``f()``, ``f(a)``, ``f(a, b)``.
198 |
199 | And here is the sugar:
200 |
201 | =========== ================== ===============================
202 | Sugar Meaning Example
203 | =========== ================== ===============================
204 | ``f a`` ``f(a)`` ``spawn log("some message")``
205 | ``a.f()`` ``f(a)`` ``db.fetchRow()``
206 | ``a.f`` ``f(a)`` ``mystring.len``
207 | ``f a, b`` ``f(a, b)`` ``echo "hello ", "world"``
208 | ``a.f(b)`` ``f(a, b)`` ``myarray.map(f)``
209 | ``a.f b`` ``f(a, b)`` ``db.fetchRow 1``
210 | ``f"\n"`` ``f(r"\n")`` ``re"\b[a-z*]\b"``
211 | =========== ================== ===============================
212 |
213 |
214 | **BUT**: ``f`` does not mean ``f()``; ``myarray.map(f)`` passes ``f`` to ``map``
215 |
216 |
217 | Operators
218 | =========
219 |
220 | * operators are simply sugar for functions
221 | * operator in backticks is treated like an identifier
222 |
223 | ::
224 | `@`(x, y)
225 | x.`@`(y)
226 | `@`(x)
227 | x.`@`()
228 | x.`@`
229 |
230 |
231 | Operators
232 | =========
233 |
234 | * Of course, most of the time binary operators are simply invoked as ``x @ y``
235 | and unary operators as ``@x``.
236 | * No explicit distinction between binary and unary operators:
237 |
238 | .. code-block:: Nim
239 | :number-lines:
240 |
241 | proc `++`(x: var int; y: int = 1; z: int = 0) =
242 | x = x + y + z
243 |
244 | var g = 70
245 | ++g
246 | g ++ 7
247 | g.`++`(10, 20)
248 | echo g # writes 108
249 |
250 | * parameters are readonly unless declared as ``var``
251 | * ``var`` means "pass by reference" (implemented with a hidden pointer)
252 |
253 |
254 | Control flow
255 | ============
256 |
257 |
258 | - The usual control flow statements are available:
259 | * if
260 | * case
261 | * when
262 | * while
263 | * for
264 | * try
265 | * defer
266 | * return
267 | * yield
268 |
269 |
270 | If vs when
271 | ==========
272 |
273 | .. code-block:: nim
274 | :number-lines:
275 |
276 | when defined(posix):
277 | proc getCreationTime(file: string): Time =
278 | var res: Stat
279 | if stat(file, res) < 0'i32:
280 | let error = osLastError()
281 | raiseOSError(error)
282 | return res.st_ctime
283 |
284 |
285 |
286 | Statements vs expressions
287 | =========================
288 |
289 | Statements require indentation:
290 |
291 | .. code-block:: nim
292 | # no indentation needed for single assignment statement:
293 | if x: x = false
294 |
295 | # indentation needed for nested if statement:
296 | if x:
297 | if y:
298 | y = false
299 | else:
300 | y = true
301 |
302 | # indentation needed, because two statements follow the condition:
303 | if x:
304 | x = false
305 | y = false
306 |
307 |
308 | Statements vs expressions
309 | =========================
310 |
311 | Expressions do not:
312 |
313 | .. code-block:: nim
314 |
315 | if thisIsaLongCondition() and
316 | thisIsAnotherLongCondition(1,
317 | 2, 3, 4):
318 | x = true
319 |
320 | - Rule of thumb: optional indentation after operators, ``(`` and ``,``
321 | - ``if``, ``case`` etc also available as expressions
322 |
323 |
324 |
325 | Builtin types
326 | =============
327 |
328 | - ``int`` -- platform dependent (16) 32 or 64 bit signed number
329 | * overflows produce an exception in debug mode; wrap around in release mode
330 |
331 | - ``float`` -- 64 bit floating point number
332 | * float64 an alias for float
333 | * float32 32 bit floating point number
334 |
335 | - ``int8`` / ``int16`` / ``int32`` / ``int64``
336 | * integer types with a platform independent size
337 |
338 |
339 | Builtin types
340 | =============
341 |
342 | - ``uint`` / ``uint8`` / ``uint16`` / ``uint32`` / ``uint64``
343 | * like in C, always wrap around; modulo arithmetic
344 | * heavily discouraged: ``for in 0 .. x.len - 3``
345 | should iterate 0 times when ``x.len == 0``, not 4294967293 times!
346 | * instead: use ``Natural``
347 |
348 | - ``range[T]``
349 | * subrange type; quite heavily used in Nim
350 | (``type Natural = range[0..high(int)]``)
351 |
352 | - ``bool``
353 |
354 |
355 | Builtin types
356 | =============
357 |
358 | - ``array[FixedSize, T]``
359 | * fixed size in Nim
360 | * value based datatypes
361 | * layout is compatible to C
362 | * create via ``[1, 2, 3]`` construction
363 |
364 | - ``seq[T]``
365 | * dynamically resizable at runtime
366 | * grow with ``add``, resize with ``setLen``
367 | * create via ``@`` or ``newSeq``: ``@[1, 2, 3]``
368 | * allocated on the heap and GC'ed
369 |
370 | - ``openArray[T]``
371 | * allows to pass ``seq`` or ``array`` to a routine
372 | * internally a (pointer, length) pair
373 |
374 |
375 | Builtin types
376 | =============
377 |
378 | - ``proc (a, b: string) {.closure.}``
379 | * functions are first class in Nim
380 | * "calling convention" affects type compatibility
381 | * ``closure`` is a special calling convention (closures are GC'ed)
382 |
383 | - ``char`` / ``string`` / ``cstring``
384 | * ``char`` is simply an octet, ``string`` is almost a ``seq[char]``.
385 | * ``string`` is (usually) allocated on the heap and GC'ed
386 |
387 |
388 | Builtin types
389 | =============
390 |
391 | ``tuple``
392 |
393 | * value based datatypes
394 | * structural typing
395 | * optional field names
396 | * construct with ``()``
397 |
398 | .. code-block:: Nim
399 | :number-lines:
400 |
401 | proc `+-`(x, y: int): (int, int) = (x - y, x + y)
402 | # alternatively
403 | proc `+-`(x, y: int): tuple[lowerBound, upperBound: int] = (x - y, x + y)
404 |
405 | let tup = 100 +- 10
406 | echo tup[0], " ", tup.upperBound
407 |
408 | # tuple unpacking
409 | let (lower, _) = 100 +- 10
410 |
411 |
412 | Builtin types
413 | =============
414 |
415 | ``object``
416 |
417 | * value based datatypes
418 |
419 | .. code-block:: nim
420 | :number-lines:
421 |
422 | type
423 | Rect = object
424 | x, y, w, h: int
425 |
426 | # construction:
427 | let r = Rect(x: 12, y: 22, w: 40, h: 80)
428 |
429 | # field access:
430 | echo r.x, " ", r.y
431 |
432 |
433 | Builtin types
434 | =============
435 |
436 | enums & sets
437 |
438 | .. code-block:: nim
439 | :number-lines:
440 |
441 | type
442 | SandboxFlag* = enum ## what the interpreter should allow
443 | allowCast, ## allow unsafe language feature: 'cast'
444 | allowFFI, ## allow the FFI
445 | allowInfiniteLoops ## allow endless loops
446 | SandboxFlags* = set[SandboxFlag]
447 |
448 | proc runNimCode(code: string; flags: SandboxFlags = {allowCast, allowFFI}) =
449 | ...
450 |
451 |
452 | Builtin types
453 | =============
454 |
455 | .. code-block:: C
456 | :number-lines:
457 |
458 | #define allowCast (1 << 0)
459 | #define allowFFI (1 << 1)
460 | #define allowInfiniteLoops (1 << 1)
461 |
462 | void runNimCode(char* code, unsigned int flags = allowCast|allowFFI);
463 |
464 | runNimCode("4+5", 700);
465 |
466 |
467 | Builtin types
468 | =============
469 |
470 | ``ref`` and ``ptr``
471 |
472 | * pointers; ``ref`` is a "traced" pointer, ``ptr`` is an "untraced" pointer
473 | * ``string``, ``seq``, ``ref`` and ``closure`` are GC'ed, nothing else
474 | * ``ref object`` an idiom to get reference semantics out of objects
475 |
476 |
477 | Regular expressions
478 | ===================
479 |
480 | .. code-block:: nim
481 | :number-lines:
482 |
483 | # Model a regular expression
484 | type
485 | RegexKind = enum ## the regex AST's kind
486 | reChar, ## character node "c"
487 | reCClass, ## character class node "[a-z]"
488 | reStar, ## star node "r*"
489 | rePlus, ## plus node "r+"
490 | reOpt, ## option node "r?"
491 | reCat, ## concatenation node "ab"
492 | reAlt, ## alternatives node "a|b"
493 | reWordBoundary ## "\b"
494 |
495 | RegExpr = ref object
496 | case kind: RegexKind
497 | of reWordBoundary: discard
498 | of reChar:
499 | c: char
500 | of reCClass:
501 | cc: set[char]
502 | of reStar, rePlus, reOpt:
503 | child0: RegExpr
504 | of reCat, reAlt:
505 | child1, child2: RegExpr
506 |
507 |
508 | Equality
509 | ========
510 |
511 | .. code-block:: nim
512 | :number-lines:
513 |
514 | proc `==`(a, b: RegExpr): bool =
515 | if a.kind == b.kind:
516 | case a.kind
517 | of reWordBoundary: result = true
518 | of reChar: result = a.c == b.c
519 | of reCClass: result = a.cc == b.cc
520 | of reStar, rePlus, reOpt: result = `==`(a.child0, b.child0)
521 | of reCat, reAlt: result = `==`(a.child1, b.child1) and
522 | `==`(a.child2, b.child2)
523 |
524 |
525 | Accessors
526 | =========
527 |
528 | .. code-block:: nim
529 | :number-lines:
530 |
531 | type
532 | HashTable[K, V] = object
533 | data: seq[(K, V)]
534 |
535 | proc hash[K](k: K): int = 0
536 |
537 | proc `[]`*[K, V](x: HashTable[K, V]; k: K): V =
538 | result = x.data[hash(k)][1]
539 |
540 | proc `[]=`*[K, V](x: var HashTable[K, V]; k: K, v: V) =
541 | x.data[hash(k)][1] = v
542 |
543 |
544 | proc initHashTable[K, V](): HashTable[K, V] =
545 | result.data = @[]
546 |
547 | var tab = initHashTable[string, string]()
548 | tab["key"] = "abc" # calls '[]=' accessor
549 |
550 | echo tab["key"] # calls '[]' accessor
551 |
552 |
553 | Accessors
554 | =========
555 |
556 | .. code-block:: nim
557 | :number-lines:
558 |
559 | type
560 | HashTable[K, V] = object
561 | data: seq[(K, V)]
562 |
563 | proc hash[K](k: K): int = 0
564 |
565 | proc `[]`*[K, V](x: HashTable[K, V]; k: K): V =
566 | result = x.data[hash(k)][1]
567 |
568 | proc `[]=`*[K, V](x: var HashTable[K, V]; k: K, v: V) =
569 | x.data[hash(k)][1] = v
570 |
571 |
572 | proc initHashTable[K, V](): HashTable[K, V] =
573 | result.data = @[]
574 |
575 | var tab = initHashTable[string, string]()
576 | tab["key"] = "abc" # calls '[]=' accessor
577 |
578 | echo tab["key"] # calls '[]' accessor
579 |
580 | # ouch:
581 | tab["key"].add "xyz"
582 |
583 |
584 | Accessors
585 | =========
586 |
587 | .. code-block:: nim
588 | :number-lines:
589 |
590 |
591 | proc `[]`*[Key, Value](x: var HashTable[Key, Value]; k: Key): var Value =
592 | result = x.data[hash(key)]
593 |
594 |
595 | var
596 | tab = initHashTable[string, string]()
597 |
598 | # compiles :-)
599 | tab["key"].add "xyz"
600 |
601 |
602 | * ``var`` "pass by reference" for parameters
603 | * can also by used for return values
604 |
605 |
606 | Distinct
607 | ========
608 |
609 | .. code-block:: nim
610 | :number-lines:
611 |
612 | # Taken from system.nim
613 | const taintMode = compileOption("taintmode")
614 |
615 | when taintMode:
616 | type TaintedString* = distinct string
617 | proc len*(s: TaintedString): int {.borrow.}
618 | else:
619 | type TaintedString* = string
620 |
621 | proc readLine*(f: File): TaintedString {.tags: [ReadIOEffect], benign.}
622 |
623 |
624 | Distinct
625 | ========
626 |
627 | .. code-block:: nim
628 | :number-lines:
629 | # taintmode_ex
630 |
631 | echo readLine(stdin)
632 |
633 | ::
634 | nim c -r --taintMode:on taintmode_ex
635 |
636 |
637 |
638 | Distinct
639 | ========
640 |
641 | .. code-block:: nim
642 | :number-lines:
643 | # taintmode_ex
644 |
645 | echo readLine(stdin).string
646 |
647 | ::
648 | nim c -r --taintMode:on taintmode_ex
649 |
650 |
651 |
652 | Distinct
653 | ========
654 |
655 | .. code-block:: nim
656 | :number-lines:
657 | # taintmode_ex
658 |
659 | proc `$`(x: TaintedString): string {.borrow.} # but: defeats the purpose
660 |
661 | echo readLine(stdin)
662 |
663 | ::
664 | nim c -r --taintMode:on taintmode_ex
665 |
666 |
667 | Module system
668 | =============
669 |
670 | .. code-block::nim
671 | :number-lines:
672 |
673 | # Module A
674 | var
675 | global*: string = "A.global"
676 |
677 | proc p*(x: string) = echo "exported ", x
678 |
679 |
680 | .. code-block::nim
681 | :number-lines:
682 |
683 | # Module B
684 | import A
685 |
686 | echo p(global)
687 |
688 |
689 | Module system
690 | =============
691 |
692 | .. code-block::nim
693 | :number-lines:
694 |
695 | # Module A
696 | var
697 | global*: string = "A.global"
698 |
699 | proc p*(x: string) = echo "exported ", x
700 |
701 |
702 | .. code-block::nim
703 | :number-lines:
704 |
705 | # Module B
706 | from A import p
707 |
708 | echo p(A.global)
709 |
710 |
711 | Module system
712 | =============
713 |
714 | .. code-block::nim
715 | :number-lines:
716 |
717 | # Module A
718 | var
719 | global*: string = "A.global"
720 |
721 | proc p*(x: string) = echo "exported ", x
722 |
723 |
724 | .. code-block::nim
725 | :number-lines:
726 |
727 | # Module B
728 | import A except global
729 |
730 | echo p(A.global)
731 |
732 |
733 |
734 | Routines
735 | ========
736 |
737 | - ``proc``
738 | - ``iterator``
739 | - ``template``
740 | - ``macro``
741 | - ``method``
742 | - ``converter``
743 | - (``func``)
744 |
745 |
746 | Iterators
747 | =========
748 |
749 | .. code-block:: nim
750 | :number-lines:
751 |
752 | iterator `..<`(a, b: int): int =
753 | var i = a
754 | while i < b:
755 | yield i
756 | i += 1
757 |
758 | for i in 0..<10:
759 | echo i+1, "-th iteration"
760 |
761 |
762 | Iterators
763 | =========
764 |
765 | .. code-block:: nim
766 | :number-lines:
767 |
768 | for x in [1, 2, 3]:
769 | echo x
770 |
771 |
772 |
773 | Iterators
774 | =========
775 |
776 | .. code-block:: nim
777 | :number-lines:
778 |
779 | for x in [1, 2, 3]:
780 | echo x
781 |
782 |
783 | Rewritten to:
784 |
785 |
786 | .. code-block:: nim
787 | :number-lines:
788 |
789 | for x in items([1, 2, 3]):
790 | echo x
791 |
792 | ..
793 | for i, x in foobar is rewritten to use the pairs iterator
794 |
795 |
796 | Iterators
797 | =========
798 |
799 | .. code-block:: nim
800 | :number-lines:
801 |
802 | iterator items*[IX, T](a: array[IX, T]): T {.inline.} =
803 | var i = low(IX)
804 | while i <= high(IX):
805 | yield a[i]
806 | i += 1
807 |
808 |
809 | Iterators
810 | =========
811 |
812 | .. code-block:: nim
813 | :number-lines:
814 |
815 | for x in [1, 2, 3]:
816 | x = 0 # doesn't compile
817 |
818 |
819 |
820 | Iterators
821 | =========
822 |
823 | .. code-block:: nim
824 | :number-lines:
825 |
826 | var a = [1, 2, 3]
827 | for x in a:
828 | x = 0 # doesn't compile
829 |
830 |
831 | Iterators
832 | =========
833 |
834 | .. code-block:: nim
835 | :number-lines:
836 |
837 | iterator mitems*[IX, T](a: var array[IX, T]): var T {.inline.} =
838 | var i = low(IX)
839 | if i <= high(IX):
840 | while true:
841 | yield a[i]
842 | if i >= high(IX): break
843 | i += 1
844 |
845 | var a = [1, 2, 3]
846 | for x in mitems(a):
847 | x = 0 # compiles
848 |
849 |
850 | Parallelism
851 | ===========
852 |
853 | .. code-block::nim
854 | :number-lines:
855 |
856 | import tables, strutils
857 |
858 | proc countWords(filename: string): CountTableRef[string] =
859 | ## Counts all the words in the file.
860 | result = newCountTable[string]()
861 | for word in readFile(filename).split:
862 | result.inc word
863 |
864 |
865 | Parallelism
866 | ===========
867 |
868 | .. code-block::nim
869 | :number-lines:
870 |
871 | #
872 | #
873 | const
874 | files = ["data1.txt", "data2.txt", "data3.txt", "data4.txt"]
875 |
876 | proc main() =
877 | var tab = newCountTable[string]()
878 | for f in files:
879 | let tab2 = countWords(f)
880 | tab.merge(tab2)
881 | tab.sort()
882 | echo tab.largest
883 |
884 | main()
885 |
886 |
887 | Parallelism
888 | ===========
889 |
890 | .. code-block::nim
891 | :number-lines:
892 |
893 | import threadpool
894 |
895 | const
896 | files = ["data1.txt", "data2.txt", "data3.txt", "data4.txt"]
897 |
898 | proc main() =
899 | var tab = newCountTable[string]()
900 | var results: array[files.len, ***FlowVar[CountTableRef[string]]***]
901 | for i, f in files:
902 | results[i] = ***spawn*** countWords(f)
903 | for i in 0..high(results):
904 | tab.merge(*** ^results[i] ***)
905 | tab.sort()
906 | echo tab.largest
907 |
908 | main()
909 |
--------------------------------------------------------------------------------
/2_meta.rst:
--------------------------------------------------------------------------------
1 | =================================================================
2 | Meta programming
3 | =================================================================
4 |
5 |
6 | Templates
7 | =========
8 |
9 | * templates are declarative, macros imperative
10 |
11 | .. code-block:: nim
12 | # from System.nim
13 | template `!=` (a, b: untyped): untyped =
14 | not (a == b)
15 |
16 | assert(5 != 6) # rewritten to: assert(not (5 == 6))
17 |
18 | * more transformations
19 | - ``a > b`` is rewritten to ``b < a``.
20 | - ``a in b`` is rewritten to ``contains(b, a)``.
21 | - ``a notin b`` is rewritten to ``not (a in b)``.
22 | - ``a isnot b`` is rewritten to ``not (a is b)``.
23 |
24 |
25 | Templates
26 | =========
27 |
28 | .. code-block:: nim
29 | :number-lines:
30 |
31 | template html(name, body) =
32 | proc name(): string =
33 | result = ""
34 | body
35 | result.add("")
36 |
37 | html mainPage:
38 | echo "colon syntax to pass statements to template"
39 |
40 |
41 |
42 | Templates
43 | =========
44 |
45 | Templates already suffice to implement simple DSLs:
46 |
47 | .. code-block:: nim
48 | :number-lines:
49 |
50 | html mainPage:
51 | head:
52 | title "The Nim programming language"
53 | body:
54 | ul:
55 | li "efficient"
56 | li "expressive"
57 | li "elegant"
58 |
59 | echo mainPage()
60 |
61 |
62 | Produces::
63 |
64 |
65 | The Nim programming language
66 |
67 |
68 | - efficient
69 | - expressive
70 | - elegant
71 |
72 |
73 |
74 |
75 |
76 | Templates
77 | =========
78 |
79 | .. code-block:: nim
80 | template html(name, body) =
81 | proc name(): string =
82 | result = ""
83 | body
84 | result.add("")
85 |
86 | template head(body) =
87 | result.add("")
88 | body
89 | result.add("")
90 |
91 | ...
92 |
93 | template title(x) =
94 | result.add("$1" % x)
95 |
96 | template li(x) =
97 | result.add("$1" % x)
98 |
99 |
100 | Templates
101 | =========
102 |
103 | .. code-block:: nim
104 | :number-lines:
105 |
106 | proc mainPage(): string =
107 | result = ""
108 | result.add("")
109 | result.add("$1" % "The Nim programming language")
110 | result.add("")
111 | result.add("")
112 | result.add("")
113 | result.add("- $1
" % "efficient")
114 | result.add("- $1
" % "expressive")
115 | result.add("- $1
" % "elegant")
116 | result.add("
")
117 | result.add("")
118 | result.add("")
119 |
120 |
121 | Macros
122 | ======
123 |
124 | * imperative AST to AST transformations
125 | * Turing complete
126 | * ``macros`` module provides an API for dealing with Nim ASTs
127 |
128 |
129 |
130 | Code coverage
131 | =============
132 |
133 | .. code-block:: nim
134 | :number-lines:
135 |
136 | proc toTest(x, y: int) =
137 | try:
138 | case x
139 | of 8:
140 | if y > 9: echo "8.1"
141 | else: echo "8.2"
142 | of 9: echo "9"
143 | else: echo "else"
144 | echo "no exception"
145 | except IoError:
146 | echo "IoError"
147 |
148 | toTest(8, 10)
149 | toTest(10, 10)
150 |
151 |
152 | Code coverage
153 | =============
154 |
155 | .. code-block:: nim
156 | :number-lines:
157 |
158 | proc toTest(x, y: int) =
159 | try:
160 | case x
161 | of 8:
162 | if y > 9: echo "8.1"
163 | else: ***echo "8.2"***
164 | of 9: ***echo "9"***
165 | else: echo "else"
166 | echo "no exception"
167 | except IoError:
168 | ***echo "IoError"***
169 |
170 | toTest(8, 10)
171 | toTest(10, 10)
172 |
173 |
174 |
175 | Code coverage
176 | =============
177 |
178 | .. code-block:: nim
179 | :number-lines:
180 | # This is the code our macro will produce!
181 |
182 | var
183 | track = [("line 11", false), ("line 15", false), ...]
184 |
185 | proc toTest(x, y: int) =
186 | try:
187 | case x
188 | of 8:
189 | if y > 9:
190 | track[0][1] = true
191 | echo "8.1"
192 | else:
193 | track[1][1] = true
194 | echo "8.2"
195 | of 9:
196 | track[2][1] = true
197 | echo "9"
198 | else:
199 | track[3][1] = true
200 | echo "foo"
201 | echo "no exception"
202 | except IoError:
203 | track[4][1] = true
204 | echo "IoError"
205 |
206 |
207 | Code coverage
208 | =============
209 |
210 | .. code-block:: nim
211 | :number-lines:
212 |
213 | toTest(8, 10)
214 | toTest(1, 2)
215 |
216 | proc listCoverage(s: openArray[(string, bool)]) =
217 | for x in s:
218 | if not x[1]: echo "NOT COVERED ", x[0]
219 |
220 | listCoverage(track)
221 |
222 |
223 | Code coverage
224 | =============
225 |
226 | .. code-block:: nim
227 | :number-lines:
228 |
229 | import macros
230 |
231 | macro cov(n: untyped): untyped =
232 | result = n
233 | echo treeRepr n
234 |
235 | cov:
236 | proc toTest(x, y: int) =
237 | try:
238 | case x
239 | of 8:
240 | if y > 9: echo "8.1"
241 | else: echo "8.2"
242 | of 9: echo "9"
243 | else: echo "foo"
244 | echo "no exception"
245 | except IoError:
246 | echo "IoError"
247 |
248 | toTest(8, 10)
249 | toTest(10, 10)
250 |
251 |
252 | Code coverage
253 | =============
254 |
255 | ::
256 | ...
257 | TryStmt
258 | StmtList
259 | CaseStmt
260 | Ident !"x"
261 | OfBranch
262 | IntLit 8
263 | StmtList
264 | IfStmt
265 | ElifBranch
266 | Infix
267 | Ident !">"
268 | Ident !"y"
269 | IntLit 9
270 | StmtList [...]
271 | Else
272 | StmtList [...]
273 | OfBranch
274 | IntLit 9
275 | StmtList
276 | Command
277 | Ident !"echo"
278 | StrLit 9
279 | Else
280 | StmtList
281 | Command
282 | Ident !"echo"
283 | StrLit foo
284 | Command [...]
285 | ExceptBranch
286 | [...]
287 |
288 |
289 |
290 | Code coverage
291 | =============
292 |
293 | .. code-block:: nim
294 | :number-lines:
295 |
296 | ## Code coverage macro
297 |
298 | import macros
299 |
300 | proc transform(n, track, list: NimNode): NimNode {.compileTime.} =
301 | ...
302 |
303 | macro cov(body: untyped): untyped =
304 | var list = newNimNode(nnkBracket)
305 | let track = genSym(nskVar, "track")
306 | result = transform(body, track, list)
307 | result = newStmtList(newVarStmt(track, list), result,
308 | newCall(bindSym"listCoverage", track))
309 | echo result.toStrLit
310 |
311 |
312 | cov:
313 | proc toTest(x, y: int) =
314 | ...
315 |
316 | toTest(8, 10)
317 | toTest(10, 10)
318 |
319 |
320 | Macros
321 | ======
322 |
323 | .. code-block:: nim
324 | :number-lines:
325 |
326 | proc transform(n, track, list: NimNode): NimNode {.compileTime.} =
327 | # recurse:
328 | result = copyNimNode(n)
329 | for c in n.children:
330 | result.add c.transform(track, list)
331 |
332 | if n.kind in {nnkElifBranch, nnkOfBranch, nnkExceptBranch, nnkElse}:
333 | let lineinfo = result[^1].lineinfo
334 |
335 | template trackStmt(track, i) =
336 | track[i][1] = true
337 | result[^1] = newStmtList(getAst trackStmt(track, list.len), result[^1])
338 |
339 | template tup(lineinfo) =
340 | (lineinfo, false)
341 | list.add(getAst tup(lineinfo))
342 |
343 |
344 | Macros
345 | ======
346 |
347 | Result::
348 | 8.1
349 | no exception
350 | else
351 | no exception
352 | NOT COVERED coverage.nim(42,14)
353 | NOT COVERED coverage.nim(43,12)
354 | NOT COVERED coverage.nim(47,6)
355 |
356 |
357 | Macros
358 | ======
359 |
360 | .. code-block:: nim
361 | :number-lines:
362 |
363 | proc toTest(x, y: int) =
364 | try:
365 | case x
366 | of 8:
367 | if y > 9: echo "8.1"
368 | else: ***echo "8.2"***
369 | of 9: ***echo "9"***
370 | else: echo "else"
371 | echo "no exception"
372 | except IoError:
373 | ***echo "IoError"***
374 |
375 | toTest(8, 10)
376 | toTest(10, 10)
377 |
378 |
379 |
--------------------------------------------------------------------------------
/3_effects.rst:
--------------------------------------------------------------------------------
1 | =============
2 | Effect system
3 | =============
4 |
5 |
6 | NoSideEffect
7 | ============
8 |
9 | .. code-block:: nim
10 | :number-lines:
11 |
12 | cov:
13 | proc toTest(x, y: int): int {.noSideEffect.} =
14 | case x
15 | of 8:
16 | if y > 9: 8+1
17 | else: 8+2
18 | of 9: 9
19 | else: 100
20 |
21 | # Error: 'toTest' can have side-effects
22 |
23 |
24 |
25 | NoSideEffect
26 | ============
27 |
28 | .. code-block:: nim
29 | :number-lines:
30 |
31 | var
32 | track = [("line 9", false), ("line 13", false), ...]
33 |
34 | proc toTest(x, y: int): int {.noSideEffect.} =
35 | case x
36 | of 8:
37 | if y > 9:
38 | track[0][1] = true
39 | ...
40 |
41 |
42 |
43 | NoSideEffect
44 | ============
45 |
46 | .. code-block:: nim
47 | :number-lines:
48 |
49 | var
50 | track = [("line 9", false), ("line 13", false), ...]
51 |
52 | proc setter(x: int) =
53 | track[x][1] = true
54 |
55 | type HideEffects = proc (x: int) {.noSideEffect, raises: [], tags: [].}
56 |
57 | proc toTest(x, y: int): int =
58 | case x
59 | of 8:
60 | if y > 9:
61 | cast[HideEffects](setter)(0)
62 | ...
63 |
64 |
65 | Effect System
66 | =============
67 |
68 | - tracks side effects
69 | - tracks exceptions
70 | - tracks "tags": ReadIOEffect, WriteIoEffect, TimeEffect,
71 | ReadDirEffect, **ExecIOEffect**
72 | - tracks locking levels; deadlock prevention at compile-time
73 |
74 | ..
75 | Think of ``(T, E)`` as opposed to ``E[T]``.
76 |
77 |
78 | Exceptions
79 | ==========
80 |
81 | .. code-block:: nim
82 | :number-lines:
83 |
84 | import strutils
85 |
86 | proc readFromFile() {.raises: [].} =
87 | # read the first two lines of a text file that should contain numbers
88 | # and tries to add them
89 | var
90 | f: File
91 | if open(f, "numbers.txt"):
92 | try:
93 | var a = readLine(f)
94 | var b = readLine(f)
95 | echo("sum: " & $(parseInt(a) + parseInt(b)))
96 | except OverflowError:
97 | echo("overflow!")
98 | except ValueError:
99 | echo("could not convert string to integer")
100 | except IOError:
101 | echo("IO error!")
102 | except:
103 | echo("Unknown exception!")
104 | finally:
105 | close(f)
106 |
107 | ..
108 | - describe inference algorithm
109 |
110 | proc noRaise(x: proc()) {.raises: [].} =
111 | # unknown call that might raise anything, but valid:
112 | x()
113 |
114 | proc doRaise() {.raises: [IOError].} =
115 | raise newException(IOError, "IO")
116 |
117 | proc use() {.raises: [].} =
118 | # doesn't compile! Can raise IOError!
119 | noRaise(doRaise)
120 |
121 |
122 | Tags
123 | ====
124 |
125 | .. code-block:: nim
126 | :number-lines:
127 | type
128 | TagA = object of RootEffect
129 | TagB = object of RootEffect
130 |
131 | proc a() {.tags: [TagA].} = discard
132 | proc b() {.tags: [TagB].} = discard
133 |
134 | proc x(input: int) {.tags: [ ? ].} =
135 | if input < 0: a()
136 | else: b()
137 |
138 | ..
139 | Just demonstrate 'doc2' here
140 |
141 |
142 | Tags
143 | ====
144 |
145 | .. code-block:: nim
146 | :number-lines:
147 | type
148 | TagA = object of RootEffect
149 | TagB = object of RootEffect
150 |
151 | proc a() {.tags: [TagA].} = discard
152 | proc b() {.tags: [TagB].} = discard
153 |
154 | proc x(input: int) {.tags: [TagA, TagB].} =
155 | if input < 0: a()
156 | else: b()
157 |
158 |
159 | Tags
160 | ====
161 |
162 | .. code-block:: nim
163 | :number-lines:
164 |
165 | proc execProcesses(commands: openArray[string],
166 | beforeRunEvent: proc (command: string) = nil): int
167 | {.tags: [ExecIOEffect].}
168 | ## executes the commands in parallel. The highest return value of
169 | ## all processes is returned. Runs `beforeRunEvent` before running each
170 | ## command.
171 |
172 | proc echoCommand(command: string) {.tags: [WriteIOEffect].} =
173 | echo command
174 |
175 | proc compose*() =
176 | execProcesses(["gcc -o foo foo.c",
177 | "gcc -o bar bar.c",
178 | "gcc -o baz baz.c"],
179 | echoCommand)
180 |
181 |
182 |
183 | GC safety
184 | =========
185 |
186 | - a ``spawn``'ed proc must be ``gcsafe``
187 | - ``gcsafe``: Does not access global variables containing GC'ed memory
188 | - ``noSideEffect``: Does not access global variables
189 | - ``noSideEffect`` implies ``gcsafe``
190 |
191 |
192 | GC safety
193 | =========
194 |
195 | .. code-block:: nim
196 | :number-lines:
197 |
198 | import tables, strutils, threadpool
199 |
200 | const
201 | files = ["data1.txt", "data2.txt", "data3.txt", "data4.txt"]
202 |
203 | var tab = newCountTable[string]()
204 |
205 | proc countWords(filename: string) =
206 | ## Counts all the words in the file.
207 | for word in readFile(filename).split:
208 | tab.inc word
209 |
210 | for f in files:
211 | spawn countWords(f)
212 | sync()
213 | tab.sort()
214 | echo tab.largest
215 |
216 |
217 | GC safety
218 | =========
219 |
220 | .. code-block:: nim
221 | :number-lines:
222 |
223 | import threadpool, tables, strutils
224 |
225 | {.pragma: isolated, threadvar.}
226 |
227 | var tab {.isolated.}: CountTable[string]
228 |
229 | proc rawPut(key: string) =
230 | inc(tab, key)
231 |
232 | proc put(key: string) =
233 | pinnedSpawn 0, rawPut(key)
234 |
235 | proc rawGet(): string =
236 | tab.sort()
237 | result = tab.largest()[0]
238 |
239 | proc getMax(): string =
240 | let flow = pinnedSpawn(0, rawGet())
241 | result = ^flow
242 |
243 | proc main =
244 | pinnedSpawn 0, (proc () = tab = initCountTable[string]())
245 | for x in split(readFile("readme.txt")):
246 | put x
247 | echo getMax()
248 |
249 | main()
250 |
251 |
252 |
253 | Guards and locks
254 | ================
255 |
256 | - common low level concurrency mechanisms like locks, atomic instructions or
257 | condition variables are available
258 | - guards fight data races
259 | - locking levels fight deadlocks
260 |
261 |
262 | Data race
263 | =========
264 |
265 | A data race occurs when:
266 |
267 | - two or more threads access the same memory location concurrently
268 | - at least one of the accesses is for writing
269 | - the threads are not using any exclusive locks to control their accesses
270 |
271 |
272 | Guards fight data races
273 | =======================
274 |
275 | - Object fields and global variables can be annotated via a ``guard`` pragma
276 | - Access then has to be within a ``locks`` section:
277 |
278 | .. code-block:: nim
279 | :number-lines:
280 |
281 | var glock: Lock
282 | var gdata {.guard: glock.}: int
283 |
284 | proc invalid =
285 | # invalid: unguarded access:
286 | echo gdata
287 |
288 | proc valid =
289 | # valid access:
290 | {.locks: [glock].}:
291 | echo gdata
292 |
293 |
294 | Guards fight data races
295 | =======================
296 |
297 | .. code-block:: nim
298 | :number-lines:
299 |
300 | template lock(a: Lock; body: untyped) =
301 | pthread_mutex_lock(a)
302 | {.locks: [a].}:
303 | try:
304 | body
305 | finally:
306 | pthread_mutex_unlock(a)
307 |
308 |
309 | Guards fight data races
310 | =======================
311 |
312 | .. code-block:: nim
313 | :number-lines:
314 |
315 | var dummyLock {.compileTime.}: int
316 | var atomicCounter {.guard: dummyLock.}: int
317 |
318 | template atomicRead(x): expr =
319 | {.locks: [dummyLock].}:
320 | memoryReadBarrier()
321 | x
322 |
323 | echo atomicRead(atomicCounter)
324 |
325 |
326 | Deadlocks
327 | =========
328 |
329 | A deadlock occurs when:
330 |
331 | - thread A acquires lock L1
332 | - thread B acquires lock L2
333 | - thread A tries to acquire lock L2
334 | - thread B tries to acquire lock L1
335 |
336 | Solution?
337 |
338 |
339 | Deadlocks
340 | =========
341 |
342 | A deadlock occurs when:
343 |
344 | - thread A acquires lock L1
345 | - thread B acquires lock L2
346 | - thread A tries to acquire lock L2
347 | - thread B tries to acquire lock L1
348 |
349 | Solution?
350 |
351 | - enforce L1 is always acquired before L2
352 |
353 |
354 |
355 | Locking levels fight deadlocks
356 | ==============================
357 |
358 | .. code-block:: nim
359 | :number-lines:
360 |
361 | var a, b: Lock[2]
362 | var x: Lock[1]
363 | # invalid locking order: Lock[1] cannot be acquired before Lock[2]:
364 | {.locks: [x].}:
365 | {.locks: [a].}:
366 | ...
367 | # valid locking order: Lock[2] acquired before Lock[1]:
368 | {.locks: [a].}:
369 | {.locks: [x].}:
370 | ...
371 |
372 | # invalid locking order: Lock[2] acquired before Lock[2]:
373 | {.locks: [a].}:
374 | {.locks: [b].}:
375 | ...
376 |
377 | # valid locking order, locks of the same level acquired at the same time:
378 | {.locks: [a, b].}:
379 | ...
380 |
381 |
382 |
383 | Locking levels fight deadlocks
384 | ==============================
385 |
386 | .. code-block:: nim
387 | :number-lines:
388 |
389 | template multilock(a, b: ptr Lock; body: stmt) =
390 | if cast[ByteAddress](a) < cast[ByteAddress](b):
391 | pthread_mutex_lock(a)
392 | pthread_mutex_lock(b)
393 | else:
394 | pthread_mutex_lock(b)
395 | pthread_mutex_lock(a)
396 | {.locks: [a, b].}:
397 | try:
398 | body
399 | finally:
400 | pthread_mutex_unlock(a)
401 | pthread_mutex_unlock(b)
402 |
403 |
404 | Locking levels fight deadlocks
405 | ==============================
406 |
407 | .. code-block:: nim
408 | :number-lines:
409 |
410 | proc p() {.locks: 3.} = discard
411 |
412 | var a: Lock[4]
413 | {.locks: [a].}:
414 | # p's locklevel (3) is strictly less than a's (4) so the call is allowed:
415 | p()
416 |
--------------------------------------------------------------------------------
/4_cppinterop.rst:
--------------------------------------------------------------------------------
1 | ======================
2 | Interfacing with C/C++
3 | ======================
4 |
5 |
6 | Interfacing with C
7 | ==================
8 |
9 | 2 options
10 |
11 | - via ``dynlib``
12 | - via ``header``
13 |
14 |
15 | Dynlib import
16 | =============
17 |
18 | .. code-block:: Nim
19 | :number-lines:
20 | type
21 | GtkWidget = object
22 | data: cint
23 | binary: cfloat
24 | compatible: char
25 |
26 | proc gtk_image_new(): ptr GtkWidget
27 | {.cdecl, dynlib: "libgtk-x11-2.0.so", importc.}
28 |
29 |
30 |
31 | Header import
32 | =============
33 |
34 | .. code-block::
35 | :number-lines:
36 |
37 | type
38 | GtkWidget {.importc: "GtkWidget_t", header: "".} = object
39 | data {.importc: "Data".}: cint
40 | binary {.importc: "Binary".}: cfloat
41 | compatible: char
42 |
43 | proc gtk_image_new(): ptr GtkWidget
44 | {.cdecl, header: "", importc.}
45 |
46 | {.passC: staticExec("pkg-config --cflags gtk").}
47 | {.passL: staticExec("pkg-config --libs gtk").}
48 |
49 |
50 |
51 | Header import
52 | =============
53 |
54 | .. code-block::
55 | :number-lines:
56 |
57 | proc printf(formatstr: cstring)
58 | {.header: "", importc: "printf", varargs.}
59 |
60 | printf("%s%s", "Nim strings ", "converted to cstring for you")
61 |
62 |
63 | Data exchange with C
64 | ====================
65 |
66 | ================= ==========================================================
67 | C type Nim type
68 | ================= ==========================================================
69 | ``int`` ``cint``
70 | ``unsigned long`` ``culong``
71 | ``float`` ``cfloat``
72 | ``int x[4]`` ``array[4, cint]``
73 | ``int*`` ``ptr int``
74 | ``char*`` ``cstring``
75 | ``char**`` ``cstringArray = ptr array [0..ArrayDummySize, cstring]``
76 | ================= ==========================================================
77 |
78 |
79 | Data exchange with C
80 | ====================
81 |
82 | .. code-block:: C
83 | :number-lines:
84 |
85 | int sum(int* x, size_t len) {
86 | int result = 0;
87 | for (size_t i = 0; i < len; i++)
88 | result += x[i];
89 | return result;
90 | }
91 |
92 |
93 | Data exchange with C
94 | ====================
95 |
96 | .. code-block:: C
97 | :number-lines:
98 |
99 | int sum(int* x, size_t len) {
100 | int result = 0;
101 | for (size_t i = 0; i < len; i++)
102 | result += x[i];
103 | return result;
104 | }
105 |
106 | .. code-block:: Nim
107 | :number-lines:
108 |
109 | proc sum(x: ptr cint; len: int): cint
110 | {.importc: "sum", cdecl, header: "foo.h".}
111 |
112 | proc callSum =
113 | var x = @[1.cint, 2, 3, 4]
114 | echo sum(addr x[0], x.len)
115 |
116 | var y = [1.cint, 2, 3, 4]
117 | echo sum(addr y[0], y.len)
118 |
119 |
120 |
121 | CodegenDecl pragma
122 | ==================
123 |
124 |
125 | .. code-block:: nim
126 | :number-lines:
127 |
128 | var
129 | a {.codegenDecl: "$# progmem $#".}: int
130 |
131 | proc myinterrupt() {.codegenDecl: "__interrupt $# $#$#".} =
132 | echo "realistic interrupt handler"
133 |
134 |
135 |
136 |
137 |
138 | Wrapping C++
139 | ============
140 |
141 | .. code-block:: C++
142 | :number-lines:
143 |
144 | class Foo {
145 | public:
146 | int value;
147 | int GetValue() { return value; }
148 | int& SetValue(int x) { field = x; return &field; }
149 | };
150 |
151 | .. code-block:: Nim
152 | :number-lines:
153 |
154 | type
155 | Foo* {.importcpp: "Foo", header: "file.h".} = object
156 | value*: cint
157 |
158 | proc getValue*(this: var Foo): cint
159 | {.importcpp: "GetValue", header: "file.h".}
160 | proc setValue*(this: var Foo; x: cint): var cint
161 | {.importcpp: "SetValue", header: "file.h".}
162 |
163 |
164 | Wrapping C++
165 | ============
166 |
167 | .. code-block:: C++
168 | :number-lines:
169 |
170 | class Foo {
171 | public:
172 | int value;
173 | int GetValue() { return value; }
174 | int& SetValue(int x) { field = x; return &field; }
175 | };
176 |
177 | .. code-block:: Nim
178 | :number-lines:
179 |
180 | type
181 | Foo* {.importcpp: "Foo", header: "file.h".} = object
182 | value*: cint
183 |
184 | proc getValue*(this: var Foo): cint
185 | {.importcpp: "#.GetValue(@)", header: "file.h".}
186 | proc setValue*(this: var Foo; x: cint): var cint
187 | {.importcpp: "#.SetValue(@)", header: "file.h".}
188 |
189 |
190 |
191 | Constructors
192 | ============
193 |
194 | .. code-block:: C++
195 | :number-lines:
196 |
197 | class Foo {
198 | public:
199 | int value;
200 | int GetValue() { return value; }
201 | int& SetValue(int x) { field = x; return &field; }
202 |
203 | Foo(int x): field(x) {}
204 | };
205 |
206 | .. code-block:: Nim
207 | :number-lines:
208 |
209 | type
210 | Foo* {.importcpp: "Foo", header: "file.h".} = object
211 | value*: cint
212 |
213 | proc getValue*(this: var Foo): cint
214 | {.importcpp: "#.GetValue(@)", header: "file.h".}
215 | proc setValue*(this: var Foo; x: cint): var cint
216 | {.importcpp: "#.SetValue(@)", header: "file.h".}
217 |
218 | proc constructFoo*(x: cint): Foo
219 | {.importcpp: "Foo(@)", header: "file.h".}
220 |
221 |
222 | Constructors
223 | ============
224 |
225 | .. code-block:: C++
226 | :number-lines:
227 |
228 | Foo foo = Foo(1, 2, 3);
229 |
230 | auto foo = Foo(1, 2, 3);
231 |
232 |
233 | Constructors
234 | ============
235 |
236 | .. code-block:: C++
237 | :number-lines:
238 |
239 | Foo foo = Foo(1, 2, 3);
240 | // Calls copy constructor!
241 | auto foo = Foo(1, 2, 3);
242 |
243 |
244 | Constructors
245 | ============
246 |
247 | .. code-block:: C++
248 | :number-lines:
249 |
250 | Foo foo = Foo(1, 2, 3);
251 | // Calls copy constructor!
252 | auto foo = Foo(1, 2, 3);
253 |
254 | Foo foo(1, 2, 3);
255 |
256 |
257 | Constructors
258 | ============
259 |
260 | .. code-block:: Nim
261 | :number-lines:
262 |
263 | proc constructFoo*(x: cint): Foo
264 | {.importcpp: "Foo(@)", header: "file.h", constructor.}
265 |
266 |
267 | .. code-block:: nim
268 | :number-lines:
269 |
270 | proc newFoo(a, b: cint): ptr Foo {.importcpp: "new Foo(@)".}
271 |
272 | let x = newFoo(3, 4)
273 |
274 |
275 | proc cnew*[T](x: T): ptr T {.importcpp: "(new '*0#@)", nodecl.}
276 |
277 |
278 |
279 | Generics
280 | ========
281 |
282 | For example:
283 |
284 | .. code-block:: nim
285 | :number-lines:
286 |
287 | type Input {.importcpp: "System::Input".} = object
288 | proc getSubsystem*[T](): ptr T
289 | {.importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.}
290 |
291 | let x: ptr Input = getSubsystem[Input]()
292 |
293 | Produces:
294 |
295 | .. code-block:: C
296 | :number-lines:
297 |
298 | x = SystemManager::getSubsystem()
299 |
300 |
301 |
302 | Emit pragma
303 | ===========
304 |
305 | .. code-block:: Nim
306 | :number-lines:
307 |
308 | {.emit: """
309 | static int cvariable = 420;
310 | """.}
311 |
312 | {.push stackTrace:off.}
313 | proc embedsC() =
314 | var nimVar = 89
315 | # use backticks to access Nim symbols within an emit section:
316 | {.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimVar`);""".}
317 | {.pop.}
318 |
319 | embedsC()
320 |
321 |
322 | ..
323 | A tour through the standard library
324 | -----------------------------------
325 |
326 | - system module: basic arithmetic and IO
327 | - strutils module; Unicode module
328 | - OS and osproc modules
329 | - sequtils and algorithm
330 | - tables and sets
331 | - linked lists, queues
332 |
333 | - watchpoints
334 | - tracing
335 | - lexer generation
336 | - ORM
337 |
338 |
339 | Questions?
340 | ==========
341 |
--------------------------------------------------------------------------------
/build.nim:
--------------------------------------------------------------------------------
1 |
2 | import strutils, os, re
3 |
4 | proc main(file: string) =
5 | discard execShellCmd("nim rst2html $1.rst" % file)
6 |
7 | const
8 | patternA = "***" &
9 | "(.*)" &
10 | "***"
11 |
12 | proc writeln(buf: var string; x: string) = buf.add x & "\n"
13 |
14 | proc tline(line: string): string =
15 | result = line.replacef(re(patternA.replace("***", r"\*\*\*"), {}),
16 | "$1")
17 | result = result.replacef(re(patternA.replace("***", r"\+\+\+"), {}),
18 | "$1")
19 | result = result.replacef(re(patternA.replace("***", r"\=\=\="), {}),
20 | "$1")
21 |
22 | var f = ""
23 | var count = 0
24 | for line in lines("$1.html" % file):
25 | if line.contains("")
29 | f.writeln("")
30 | f.writeln(line.tline)
31 | elif line.contains("
")
33 | let a = line.replace("
", "")
34 | f.writeln(a.tline)
35 | elif line.contains("