1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873 |
- =====================
- Nim Tutorial (Part I)
- =====================
- :Author: Andreas Rumpf
- :Version: |nimversion|
- .. default-role:: code
- .. include:: rstcommon.rst
- .. contents::
- Introduction
- ============
- .. raw:: html
- <blockquote><p>
- "Der Mensch ist doch ein Augentier -- schöne Dinge wünsch ich mir."
- </p></blockquote>
- This document is a tutorial for the programming language *Nim*.
- This tutorial assumes that you are familiar with basic programming concepts
- like variables, types, or statements.
- Here are several other resources for learning Nim:
- * `Nim Basics tutorial <https://narimiran.github.io/nim-basics/>`_ - a gentle
- introduction of the concepts mentioned above
- * `Learn Nim in 5 minutes <https://learnxinyminutes.com/docs/nim/>`_ - quick,
- five-minute introduction to Nim
- * `The Nim manual <manual.html>`_ - many more examples of the advanced language features
- All code examples in this tutorial, as well as the ones found in the rest of
- Nim's documentation, follow the `Nim style guide <nep1.html>`_.
- The first program
- =================
- We start the tour with a modified "hello world" program:
- .. code-block:: Nim
- :test: "nim c $1"
- # This is a comment
- echo "What's your name? "
- var name: string = readLine(stdin)
- echo "Hi, ", name, "!"
- Save this code to the file "greetings.nim". Now compile and run it::
- nim compile --run greetings.nim
- With the ``--run`` `switch <nimc.html#compiler-usage-commandminusline-switches>`_ Nim
- executes the file automatically after compilation. You can give your program
- command-line arguments by appending them after the filename::
- nim compile --run greetings.nim arg1 arg2
- Commonly used commands and switches have abbreviations, so you can also use::
- nim c -r greetings.nim
- This is a **debug version**.
- To compile a release version use::
- nim c -d:release greetings.nim
- By default, the Nim compiler generates a large number of runtime checks
- aiming for your debugging pleasure. With ``-d:release`` some checks are
- `turned off and optimizations are turned on
- <nimc.html#compiler-usage-compileminustime-symbols>`_.
- For benchmarking or production code, use the ``-d:release`` switch.
- For comparing the performance with unsafe languages like C, use the ``-d:danger`` switch
- in order to get meaningful, comparable results. Otherwise Nim might be handicapped
- by checks that are **not even available** for C.
- Though it should be pretty obvious what the program does, I will explain the
- syntax: statements which are not indented are executed when the program
- starts. Indentation is Nim's way of grouping statements. Indentation is
- done with spaces only, tabulators are not allowed.
- String literals are enclosed in double-quotes. The `var` statement declares
- a new variable named `name` of type `string` with the value that is
- returned by the `readLine <io.html#readLine,File>`_ procedure. Since the
- compiler knows that `readLine <io.html#readLine,File>`_ returns a string,
- you can leave out the type in the declaration (this is called `local type
- inference`:idx:). So this will work too:
- .. code-block:: Nim
- :test: "nim c $1"
- var name = readLine(stdin)
- Note that this is basically the only form of type inference that exists in
- Nim: it is a good compromise between brevity and readability.
- The "hello world" program contains several identifiers that are already known
- to the compiler: `echo`, `readLine <io.html#readLine,File>`_, etc.
- These built-ins are declared in the system_ module which is implicitly
- imported by any other module.
- Lexical elements
- ================
- Let us look at Nim's lexical elements in more detail: like other
- programming languages Nim consists of (string) literals, identifiers,
- keywords, comments, operators, and other punctuation marks.
- String and character literals
- -----------------------------
- String literals are enclosed in double-quotes; character literals in single
- quotes. Special characters are escaped with ``\``: ``\n`` means newline, ``\t``
- means tabulator, etc. There are also *raw* string literals:
- .. code-block:: Nim
- r"C:\program files\nim"
- In raw literals, the backslash is not an escape character.
- The third and last way to write string literals is *long-string literals*.
- They are written with three quotes: `""" ... """`; they can span over
- multiple lines and the ``\`` is not an escape character either. They are very
- useful for embedding HTML code templates for example.
- Comments
- --------
- Comments start anywhere outside a string or character literal with the
- hash character `#`. Documentation comments start with `##`:
- .. code-block:: nim
- :test: "nim c $1"
- # A comment.
- var myVariable: int ## a documentation comment
- Documentation comments are tokens; they are only allowed at certain places in
- the input file as they belong to the syntax tree! This feature enables simpler
- documentation generators.
- Multiline comments are started with `#[` and terminated with `]#`. Multiline
- comments can also be nested.
- .. code-block:: nim
- :test: "nim c $1"
- #[
- You can have any Nim code text commented
- out inside this with no indentation restrictions.
- yes("May I ask a pointless question?")
- #[
- Note: these can be nested!!
- ]#
- ]#
- Numbers
- -------
- Numerical literals are written as in most other languages. As a special twist,
- underscores are allowed for better readability: `1_000_000` (one million).
- A number that contains a dot (or 'e' or 'E') is a floating-point literal:
- `1.0e9` (one billion). Hexadecimal literals are prefixed with `0x`,
- binary literals with `0b` and octal literals with `0o`. A leading zero
- alone does not produce an octal.
- The var statement
- =================
- The var statement declares a new local or global variable:
- .. code-block::
- var x, y: int # declares x and y to have the type `int`
- Indentation can be used after the `var` keyword to list a whole section of
- variables:
- .. code-block::
- :test: "nim c $1"
- var
- x, y: int
- # a comment can occur here too
- a, b, c: string
- Constants
- =========
- Constants are symbols which are bound to a value. The constant's value
- cannot change. The compiler must be able to evaluate the expression in a
- constant declaration at compile time:
- .. code-block:: nim
- :test: "nim c $1"
- const x = "abc" # the constant x contains the string "abc"
- Indentation can be used after the `const` keyword to list a whole section of
- constants:
- .. code-block::
- :test: "nim c $1"
- const
- x = 1
- # a comment can occur here too
- y = 2
- z = y + 5 # computations are possible
- The let statement
- =================
- The `let` statement works like the `var` statement but the declared
- symbols are *single assignment* variables: After the initialization their
- value cannot change:
- .. code-block::
- let x = "abc" # introduces a new variable `x` and binds a value to it
- x = "xyz" # Illegal: assignment to `x`
- The difference between `let` and `const` is: `let` introduces a variable
- that can not be re-assigned, `const` means "enforce compile time evaluation
- and put it into a data section":
- .. code-block::
- const input = readLine(stdin) # Error: constant expression expected
- .. code-block::
- :test: "nim c $1"
- let input = readLine(stdin) # works
- The assignment statement
- ========================
- The assignment statement assigns a new value to a variable or more generally
- to a storage location:
- .. code-block::
- var x = "abc" # introduces a new variable `x` and assigns a value to it
- x = "xyz" # assigns a new value to `x`
- `=` is the *assignment operator*. The assignment operator can be
- overloaded. You can declare multiple variables with a single assignment
- statement and all the variables will have the same value:
- .. code-block::
- :test: "nim c $1"
- var x, y = 3 # assigns 3 to the variables `x` and `y`
- echo "x ", x # outputs "x 3"
- echo "y ", y # outputs "y 3"
- x = 42 # changes `x` to 42 without changing `y`
- echo "x ", x # outputs "x 42"
- echo "y ", y # outputs "y 3"
- Control flow statements
- =======================
- The greetings program consists of 3 statements that are executed sequentially.
- Only the most primitive programs can get away with that: branching and looping
- are needed too.
- If statement
- ------------
- The if statement is one way to branch the control flow:
- .. code-block:: nim
- :test: "nim c $1"
- let name = readLine(stdin)
- if name == "":
- echo "Poor soul, you lost your name?"
- elif name == "name":
- echo "Very funny, your name is name."
- else:
- echo "Hi, ", name, "!"
- There can be zero or more `elif` parts, and the `else` part is optional.
- The keyword `elif` is short for `else if`, and is useful to avoid
- excessive indentation. (The `""` is the empty string. It contains no
- characters.)
- Case statement
- --------------
- Another way to branch is provided by the case statement. A case statement is
- a multi-branch:
- .. code-block:: nim
- :test: "nim c $1"
- let name = readLine(stdin)
- case name
- of "":
- echo "Poor soul, you lost your name?"
- of "name":
- echo "Very funny, your name is name."
- of "Dave", "Frank":
- echo "Cool name!"
- else:
- echo "Hi, ", name, "!"
- As it can be seen, for an `of` branch a comma-separated list of values is also
- allowed.
- The case statement can deal with integers, other ordinal types, and strings.
- (What an ordinal type is will be explained soon.)
- For integers or other ordinal types value ranges are also possible:
- .. code-block:: nim
- # this statement will be explained later:
- from std/strutils import parseInt
- echo "A number please: "
- let n = parseInt(readLine(stdin))
- case n
- of 0..2, 4..7: echo "The number is in the set: {0, 1, 2, 4, 5, 6, 7}"
- of 3, 8: echo "The number is 3 or 8"
- However, the above code **does not compile**: the reason is that you have to cover
- every value that `n` may contain, but the code only handles the values
- `0..8`. Since it is not very practical to list every other possible integer
- (though it is possible thanks to the range notation), we fix this by telling
- the compiler that for every other value nothing should be done:
- .. code-block:: nim
- ...
- case n
- of 0..2, 4..7: echo "The number is in the set: {0, 1, 2, 4, 5, 6, 7}"
- of 3, 8: echo "The number is 3 or 8"
- else: discard
- The empty `discard statement <#procedures-discard-statement>`_ is a *do
- nothing* statement. The compiler knows that a case statement with an else part
- cannot fail and thus the error disappears. Note that it is impossible to cover
- all possible string values: that is why string cases always need an `else`
- branch.
- In general, the case statement is used for subrange types or enumerations where
- it is of great help that the compiler checks that you covered any possible
- value.
- While statement
- ---------------
- The while statement is a simple looping construct:
- .. code-block:: nim
- :test: "nim c $1"
- echo "What's your name? "
- var name = readLine(stdin)
- while name == "":
- echo "Please tell me your name: "
- name = readLine(stdin) # no `var`, because we do not declare a new variable here
- The example uses a while loop to keep asking the users for their name, as long
- as the user types in nothing (only presses RETURN).
- For statement
- -------------
- The `for` statement is a construct to loop over any element an *iterator*
- provides. The example uses the built-in `countup
- <system.html#countup.i,T,T,Positive>`_ iterator:
- .. code-block:: nim
- :test: "nim c $1"
- echo "Counting to ten: "
- for i in countup(1, 10):
- echo i
- # --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines
- The variable `i` is implicitly declared by the
- `for` loop and has the type `int`, because that is what `countup
- <system.html#countup.i,T,T,Positive>`_ returns. `i` runs through the values
- 1, 2, .., 10. Each value is `echo`-ed. This code does the same:
- .. code-block:: nim
- echo "Counting to 10: "
- var i = 1
- while i <= 10:
- echo i
- inc i # increment i by 1
- # --> Outputs 1 2 3 4 5 6 7 8 9 10 on different lines
- Since counting up occurs so often in programs, Nim also has a `..
- <system.html#...i,T,T>`_ iterator that does the same:
- .. code-block:: nim
- for i in 1 .. 10:
- ...
- Counting down can be achieved as easily (but is less often needed):
- .. code-block:: nim
- echo "Counting down from 10 to 1: "
- for i in countdown(10, 1):
- echo i
- # --> Outputs 10 9 8 7 6 5 4 3 2 1 on different lines
- Zero-indexed counting has two shortcuts `..<` and `.. ^1`
- (`backward index operator <system.html#^.t%2Cint>`_) to simplify
- counting to one less than the higher index:
- .. code-block:: nim
- for i in 0 ..< 10:
- ... # the same as 0 .. 9
- or
- .. code-block:: nim
- var s = "some string"
- for i in 0 ..< s.len:
- ...
- or
- .. code-block:: nim
- var s = "some string"
- for idx, c in s[0 .. ^1]:
- ... # ^1 is the last element, ^2 would be one before it, and so on
- Other useful iterators for collections (like arrays and sequences) are
- * `items` and `mitems`, which provides immutable and mutable elements respectively, and
- * `pairs` and `mpairs` which provides the element and an index number (immutable and mutable respectively)
- .. code-block:: nim
- :test: "nim c $1"
- for index, item in ["a","b"].pairs:
- echo item, " at index ", index
- # => a at index 0
- # => b at index 1
- Scopes and the block statement
- ------------------------------
- Control flow statements have a feature not covered yet: they open a
- new scope. This means that in the following example, `x` is not accessible
- outside the loop:
- .. code-block:: nim
- :test: "nim c $1"
- :status: 1
- while false:
- var x = "hi"
- echo x # does not work
- A while (for) statement introduces an implicit block. Identifiers
- are only visible within the block they have been declared. The `block`
- statement can be used to open a new block explicitly:
- .. code-block:: nim
- :test: "nim c $1"
- :status: 1
- block myblock:
- var x = "hi"
- echo x # does not work either
- The block's *label* (`myblock` in the example) is optional.
- Break statement
- ---------------
- A block can be left prematurely with a `break` statement. The break statement
- can leave a `while`, `for`, or a `block` statement. It leaves the
- innermost construct, unless a label of a block is given:
- .. code-block:: nim
- :test: "nim c $1"
- block myblock:
- echo "entering block"
- while true:
- echo "looping"
- break # leaves the loop, but not the block
- echo "still in block"
- echo "outside the block"
- block myblock2:
- echo "entering block"
- while true:
- echo "looping"
- break myblock2 # leaves the block (and the loop)
- echo "still in block" # it won't be printed
- echo "outside the block"
- Continue statement
- ------------------
- Like in many other programming languages, a `continue` statement starts
- the next iteration immediately:
- .. code-block:: nim
- :test: "nim c $1"
- for i in 1 .. 5:
- if i <= 3: continue
- echo i # will only print 4 and 5
- When statement
- --------------
- Example:
- .. code-block:: nim
- :test: "nim c $1"
- when system.hostOS == "windows":
- echo "running on Windows!"
- elif system.hostOS == "linux":
- echo "running on Linux!"
- elif system.hostOS == "macosx":
- echo "running on Mac OS X!"
- else:
- echo "unknown operating system"
- The `when` statement is almost identical to the `if` statement, but with these
- differences:
- * Each condition must be a constant expression since it is evaluated by the
- compiler.
- * The statements within a branch do not open a new scope.
- * The compiler checks the semantics and produces code *only* for the statements
- that belong to the first condition that evaluates to `true`.
- The `when` statement is useful for writing platform-specific code, similar to
- the `#ifdef`:c: construct in the C programming language.
- Statements and indentation
- ==========================
- Now that we covered the basic control flow statements, let's return to Nim
- indentation rules.
- In Nim, there is a distinction between *simple statements* and *complex
- statements*. *Simple statements* cannot contain other statements:
- Assignment, procedure calls, or the `return` statement are all simple
- statements. *Complex statements* like `if`, `when`, `for`, `while` can
- contain other statements. To avoid ambiguities, complex statements must always
- be indented, but single simple statements do not:
- .. code-block:: nim
- # 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* are parts of a statement that usually result in a value. The
- condition in an if statement is an example of an expression. Expressions can
- contain indentation at certain places for better readability:
- .. code-block:: nim
- if thisIsaLongCondition() and
- thisIsAnotherLongCondition(1,
- 2, 3, 4):
- x = true
- As a rule of thumb, indentation within expressions is allowed after operators,
- an open parenthesis and after commas.
- With parenthesis and semicolons `(;)` you can use statements where only
- an expression is allowed:
- .. code-block:: nim
- :test: "nim c $1"
- # computes fac(4) at compile time:
- const fac4 = (var x = 1; for i in 1..4: x *= i; x)
- Procedures
- ==========
- To define new commands like `echo <system.html#echo,varargs[typed,]>`_
- and `readLine <io.html#readLine,File>`_ in the examples, the concept of a
- *procedure* is needed. (Some languages call them *methods* or *functions*.)
- In Nim new procedures are defined with the `proc` keyword:
- .. code-block:: nim
- :test: "nim c $1"
- proc yes(question: string): bool =
- echo question, " (y/n)"
- while true:
- case readLine(stdin)
- of "y", "Y", "yes", "Yes": return true
- of "n", "N", "no", "No": return false
- else: echo "Please be clear: yes or no"
- if yes("Should I delete all your important files?"):
- echo "I'm sorry Dave, I'm afraid I can't do that."
- else:
- echo "I think you know what the problem is just as well as I do."
- This example shows a procedure named `yes` that asks the user a `question`
- and returns true if they answered "yes" (or something similar) and returns
- false if they answered "no" (or something similar). A `return` statement
- leaves the procedure (and therefore the while loop) immediately. The
- `(question: string): bool` syntax describes that the procedure expects a
- parameter named `question` of type `string` and returns a value of type
- `bool`. The `bool` type is built-in: the only valid values for `bool` are
- `true` and `false`.
- The conditions in if or while statements must be of type `bool`.
- Some terminology: in the example `question` is called a (formal) *parameter*,
- `"Should I..."` is called an *argument* that is passed to this parameter.
- Result variable
- ---------------
- A procedure that returns a value has an implicit `result` variable declared
- that represents the return value. A `return` statement with no expression is
- shorthand for `return result`. The `result` value is always returned
- automatically at the end of a procedure if there is no `return` statement at
- the exit.
- .. code-block:: nim
- :test: "nim c $1"
- proc sumTillNegative(x: varargs[int]): int =
- for i in x:
- if i < 0:
- return
- result = result + i
- echo sumTillNegative() # echoes 0
- echo sumTillNegative(3, 4, 5) # echoes 12
- echo sumTillNegative(3, 4 , -1 , 6) # echoes 7
- The `result` variable is already implicitly declared at the start of the
- function, so declaring it again with 'var result', for example, would shadow it
- with a normal variable of the same name. The result variable is also already
- initialized with the type's default value. Note that referential data types will
- be `nil` at the start of the procedure, and thus may require manual
- initialization.
- A procedure that does not have any `return` statement and does not use the
- special `result` variable returns the value of its last expression. For example,
- this procedure
- .. code-block:: nim
- :test: "nim c $1"
- proc helloWorld(): string =
- "Hello, World!"
- returns the string "Hello, World!".
- Parameters
- ----------
- Parameters are immutable in the procedure body. By default, their value cannot be
- changed because this allows the compiler to implement parameter passing in the
- most efficient way. If a mutable variable is needed inside the procedure, it has
- to be declared with `var` in the procedure body. Shadowing the parameter name
- is possible, and actually an idiom:
- .. code-block:: nim
- :test: "nim c $1"
- proc printSeq(s: seq, nprinted: int = -1) =
- var nprinted = if nprinted == -1: s.len else: min(nprinted, s.len)
- for i in 0 ..< nprinted:
- echo s[i]
- If the procedure needs to modify the argument for the
- caller, a `var` parameter can be used:
- .. code-block:: nim
- :test: "nim c $1"
- proc divmod(a, b: int; res, remainder: var int) =
- res = a div b # integer division
- remainder = a mod b # integer modulo operation
- var
- x, y: int
- divmod(8, 5, x, y) # modifies x and y
- echo x
- echo y
- In the example, `res` and `remainder` are `var parameters`.
- Var parameters can be modified by the procedure and the changes are
- visible to the caller. Note that the above example would better make use of
- a tuple as a return value instead of using var parameters.
- Discard statement
- -----------------
- To call a procedure that returns a value just for its side effects and ignoring
- its return value, a `discard` statement **must** be used. Nim does not
- allow silently throwing away a return value:
- .. code-block:: nim
- discard yes("May I ask a pointless question?")
- The return value can be ignored implicitly if the called proc/iterator has
- been declared with the `discardable` pragma:
- .. code-block:: nim
- :test: "nim c $1"
- proc p(x, y: int): int {.discardable.} =
- return x + y
- p(3, 4) # now valid
- Named arguments
- ---------------
- Often a procedure has many parameters and it is not clear in which order the
- parameters appear. This is especially true for procedures that construct a
- complex data type. Therefore the arguments to a procedure can be named, so
- that it is clear which argument belongs to which parameter:
- .. code-block:: nim
- proc createWindow(x, y, width, height: int; title: string;
- show: bool): Window =
- ...
- var w = createWindow(show = true, title = "My Application",
- x = 0, y = 0, height = 600, width = 800)
- Now that we use named arguments to call `createWindow` the argument order
- does not matter anymore. Mixing named arguments with ordered arguments is
- also possible, but not very readable:
- .. code-block:: nim
- var w = createWindow(0, 0, title = "My Application",
- height = 600, width = 800, true)
- The compiler checks that each parameter receives exactly one argument.
- Default values
- --------------
- To make the `createWindow` proc easier to use it should provide `default
- values`; these are values that are used as arguments if the caller does not
- specify them:
- .. code-block:: nim
- proc createWindow(x = 0, y = 0, width = 500, height = 700,
- title = "unknown",
- show = true): Window =
- ...
- var w = createWindow(title = "My Application", height = 600, width = 800)
- Now the call to `createWindow` only needs to set the values that differ
- from the defaults.
- Note that type inference works for parameters with default values; there is
- no need to write `title: string = "unknown"`, for example.
- Overloaded procedures
- ---------------------
- Nim provides the ability to overload procedures similar to C++:
- .. code-block:: nim
- proc toString(x: int): string =
- result =
- if x < 0: "negative"
- elif x > 0: "positive"
- else: "zero"
- proc toString(x: bool): string =
- result =
- if x: "yep"
- else: "nope"
- assert toString(13) == "positive" # calls the toString(x: int) proc
- assert toString(true) == "yep" # calls the toString(x: bool) proc
- (Note that `toString` is usually the `$ <dollars.html>`_ operator in
- Nim.) The compiler chooses the most appropriate proc for the `toString`
- calls. How this overloading resolution algorithm works exactly is not
- discussed here -- see the manual for details. Ambiguous calls are reported as errors.
- Operators
- ---------
- The Nim standard library makes heavy use of overloading - one reason for this is that
- each operator like `+` is just an overloaded proc. The parser lets you
- use operators in *infix notation* (`a + b`) or *prefix notation* (`+ a`).
- An infix operator always receives two arguments, a prefix operator always one.
- (Postfix operators are not possible, because this would be ambiguous: does
- `a @ @ b` mean `(a) @ (@b)` or `(a@) @ (b)`? It always means
- `(a) @ (@b)`, because there are no postfix operators in Nim.)
- Apart from a few built-in keyword operators such as `and`, `or`, `not`,
- operators always consist of these characters:
- `+ - * \ / < > = @ $ ~ & % ! ? ^ . |`
- User-defined operators are allowed. Nothing stops you from defining your own
- `@!?+~` operator, but doing so may reduce readability.
- The operator's precedence is determined by its first character. The details
- can be `found in the manual <manual.html#syntax-precedence>`_.
- To define a new operator enclose the operator in backticks "`":
- .. code-block:: nim
- proc `$` (x: myDataType): string = ...
- # now the $ operator also works with myDataType, overloading resolution
- # ensures that $ works for built-in types just like before
- The "`" notation can also be used to call an operator just like any other
- procedure:
- .. code-block:: nim
- :test: "nim c $1"
- if `==`( `+`(3, 4), 7): echo "true"
- Forward declarations
- --------------------
- Every variable, procedure, etc. needs to be declared before it can be used.
- (The reason for this is that it is non-trivial to avoid this need in a
- language that supports metaprogramming as extensively as Nim does.)
- However, this cannot be done for mutually recursive procedures:
- .. code-block:: nim
- # forward declaration:
- proc even(n: int): bool
- .. code-block:: nim
- proc odd(n: int): bool =
- assert(n >= 0) # makes sure we don't run into negative recursion
- if n == 0: false
- else:
- n == 1 or even(n-1)
- proc even(n: int): bool =
- assert(n >= 0) # makes sure we don't run into negative recursion
- if n == 1: false
- else:
- n == 0 or odd(n-1)
- Here `odd` depends on `even` and vice versa. Thus `even` needs to be
- introduced to the compiler before it is completely defined. The syntax for
- such a forward declaration is simple: just omit the `=` and the
- procedure's body. The `assert` just adds border conditions, and will be
- covered later in `Modules`_ section.
- Later versions of the language will weaken the requirements for forward
- declarations.
- The example also shows that a proc's body can consist of a single expression
- whose value is then returned implicitly.
- Iterators
- =========
- Let's return to the simple counting example:
- .. code-block:: nim
- :test: "nim c $1"
- echo "Counting to ten: "
- for i in countup(1, 10):
- echo i
- Can a `countup <system.html#countup.i,T,T,Positive>`_ proc be written that
- supports this loop? Lets try:
- .. code-block:: nim
- proc countup(a, b: int): int =
- var res = a
- while res <= b:
- return res
- inc(res)
- However, this does not work. The problem is that the procedure should not
- only `return`, but return and **continue** after an iteration has
- finished. This *return and continue* is called a `yield` statement. Now
- the only thing left to do is to replace the `proc` keyword by `iterator`
- and here it is -- our first iterator:
- .. code-block:: nim
- :test: "nim c $1"
- iterator countup(a, b: int): int =
- var res = a
- while res <= b:
- yield res
- inc(res)
- Iterators look very similar to procedures, but there are several
- important differences:
- * Iterators can only be called from for loops.
- * Iterators cannot contain a `return` statement (and procs cannot contain a
- `yield` statement).
- * Iterators have no implicit `result` variable.
- * Iterators do not support recursion.
- * Iterators cannot be forward declared, because the compiler must be able to inline an iterator.
- (This restriction will be gone in a future version of the compiler.)
- However, you can also use a closure iterator to get a different set of
- restrictions. See `first-class iterators <manual.html#iterators-and-the-for-statement-firstminusclass-iterators>`_
- for details. Iterators can have the same name and parameters as a proc since
- essentially they have their own namespaces. Therefore it is common practice to
- wrap iterators in procs of the same name which accumulate the result of the
- iterator and return it as a sequence, like `split` from the `strutils module
- <strutils.html>`_.
- Basic types
- ===========
- This section deals with the basic built-in types and the operations
- that are available for them in detail.
- Booleans
- --------
- Nim's boolean type is called `bool` and consists of the two
- pre-defined values `true` and `false`. Conditions in while,
- if, elif, and when statements must be of type bool.
- The operators `not, and, or, xor, <, <=, >, >=, !=, ==` are defined
- for the bool type. The `and` and `or` operators perform short-circuit
- evaluation. For example:
- .. code-block:: nim
- while p != nil and p.name != "xyz":
- # p.name is not evaluated if p == nil
- p = p.next
- Characters
- ----------
- The *character type* is called `char`. Its size is always one byte, so
- it cannot represent most UTF-8 characters, but it *can* represent one of the bytes
- that makes up a multi-byte UTF-8 character.
- The reason for this is efficiency: for the overwhelming majority of use-cases,
- the resulting programs will still handle UTF-8 properly as UTF-8 was especially
- designed for this.
- Character literals are enclosed in single quotes.
- Chars can be compared with the `==`, `<`, `<=`, `>`, `>=` operators.
- The `$` operator converts a `char` to a `string`. Chars cannot be mixed
- with integers; to get the ordinal value of a `char` use the `ord` proc.
- Converting from an integer to a `char` is done with the `chr` proc.
- Strings
- -------
- String variables are **mutable**, so appending to a string
- is possible, and quite efficient. Strings in Nim are both zero-terminated and have a
- length field. A string's length can be retrieved with the builtin `len`
- procedure; the length never counts the terminating zero. Accessing the
- terminating zero is an error, it only exists so that a Nim string can be converted
- to a `cstring` without doing a copy.
- The assignment operator for strings copies the string. You can use the `&`
- operator to concatenate strings and `add` to append to a string.
- Strings are compared using their lexicographical order. All the comparison operators
- are supported. By convention, all strings are UTF-8 encoded, but this is not
- enforced. For example, when reading strings from binary files, they are merely
- a sequence of bytes. The index operation `s[i]` means the i-th *char* of
- `s`, not the i-th *unichar*.
- A string variable is initialized with the empty string `""`.
- Integers
- --------
- Nim has these integer types built-in:
- `int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64`.
- The default integer type is `int`. Integer literals can have a *type suffix*
- to specify a non-default integer type:
- .. code-block:: nim
- :test: "nim c $1"
- let
- x = 0 # x is of type `int`
- y = 0'i8 # y is of type `int8`
- z = 0'i32 # z is of type `int32`
- u = 0'u # u is of type `uint`
- Most often integers are used for counting objects that reside in memory, so
- `int` has the same size as a pointer.
- The common operators `+ - * div mod < <= == != > >=` are defined for
- integers. The `and or xor not` operators are also defined for integers and
- provide *bitwise* operations. Left bit shifting is done with the `shl`, right
- shifting with the `shr` operator. Bit shifting operators always treat their
- arguments as *unsigned*. For `arithmetic bit shifts`:idx: ordinary
- multiplication or division can be used.
- Unsigned operations all wrap around; they cannot lead to over- or under-flow
- errors.
- Lossless `Automatic type conversion`:idx: is performed in expressions where different
- kinds of integer types are used. However, if the type conversion
- would cause loss of information, the ``RangeDefect``:idx: is raised (if the error
- cannot be detected at compile time).
- Floats
- ------
- Nim has these floating-point types built-in: `float float32 float64`.
- The default float type is `float`. In the current implementation,
- `float` is always 64-bits.
- Float literals can have a *type suffix* to specify a non-default float
- type:
- .. code-block:: nim
- :test: "nim c $1"
- var
- x = 0.0 # x is of type `float`
- y = 0.0'f32 # y is of type `float32`
- z = 0.0'f64 # z is of type `float64`
- The common operators `+ - * / < <= == != > >=` are defined for
- floats and follow the IEEE-754 standard.
- Automatic type conversion in expressions with different kinds of floating-point types is performed: the smaller type is converted to the larger. Integer
- types are **not** converted to floating-point types automatically, nor vice
- versa. Use the `toInt <system.html#toInt,float>`_ and
- `toFloat <system.html#toFloat,int>`_ procs for these conversions.
- Type Conversion
- ---------------
- Conversion between numerical types is performed by using the
- type as a function:
- .. code-block:: nim
- :test: "nim c $1"
- var
- x: int32 = 1.int32 # same as calling int32(1)
- y: int8 = int8('a') # 'a' == 97'i8
- z: float = 2.5 # int(2.5) rounds down to 2
- sum: int = int(x) + int(y) + int(z) # sum == 100
- Internal type representation
- ============================
- As mentioned earlier, the built-in `$ <dollars.html>`_ (stringify) operator
- turns any basic type into a string, which you can then print to the console
- using the `echo` proc. However, advanced types, and your own custom types,
- won't work with the `$` operator until you define it for them.
- Sometimes you just want to debug the current value of a complex type without
- having to write its `$` operator. You can use then the `repr
- <system.html#repr,T>`_ proc which works with any type and even complex data
- graphs with cycles. The following example shows that even for basic types
- there is a difference between the `$` and `repr` outputs:
- .. code-block:: nim
- :test: "nim c $1"
- var
- myBool = true
- myCharacter = 'n'
- myString = "nim"
- myInteger = 42
- myFloat = 3.14
- echo myBool, ":", repr(myBool)
- # --> true:true
- echo myCharacter, ":", repr(myCharacter)
- # --> n:'n'
- echo myString, ":", repr(myString)
- # --> nim:0x10fa8c050"nim"
- echo myInteger, ":", repr(myInteger)
- # --> 42:42
- echo myFloat, ":", repr(myFloat)
- # --> 3.14:3.14
- Advanced types
- ==============
- In Nim new types can be defined within a `type` statement:
- .. code-block:: nim
- :test: "nim c $1"
- type
- biggestInt = int64 # biggest integer type that is available
- biggestFloat = float64 # biggest float type that is available
- Enumeration and object types may only be defined within a
- `type` statement.
- Enumerations
- ------------
- A variable of an enumeration type can only be assigned one of the enumeration's specified values.
- These values are a set of ordered symbols. Each symbol is mapped
- to an integer value internally. The first symbol is represented
- at runtime by 0, the second by 1, and so on. For example:
- .. code-block:: nim
- :test: "nim c $1"
- type
- Direction = enum
- north, east, south, west
- var x = south # `x` is of type `Direction`; its value is `south`
- echo x # prints "south"
- All the comparison operators can be used with enumeration types.
- An enumeration's symbol can be qualified to avoid ambiguities:
- `Direction.south`.
- The `$` operator can convert any enumeration value to its name, and the `ord`
- proc can convert it to its underlying integer value.
- For better interfacing to other programming languages, the symbols of enum
- types can be assigned an explicit ordinal value. However, the ordinal values
- must be in ascending order.
- Ordinal types
- -------------
- Enumerations, integer types, `char` and `bool` (and
- subranges) are called ordinal types. Ordinal types have quite
- a few special operations:
- ----------------- --------------------------------------------------------
- Operation Comment
- ----------------- --------------------------------------------------------
- `ord(x)` returns the integer value that is used to
- represent `x`'s value
- `inc(x)` increments `x` by one
- `inc(x, n)` increments `x` by `n`; `n` is an integer
- `dec(x)` decrements `x` by one
- `dec(x, n)` decrements `x` by `n`; `n` is an integer
- `succ(x)` returns the successor of `x`
- `succ(x, n)` returns the `n`'th successor of `x`
- `pred(x)` returns the predecessor of `x`
- `pred(x, n)` returns the `n`'th predecessor of `x`
- ----------------- --------------------------------------------------------
- The `inc <system.html#inc,T,int>`_, `dec <system.html#dec,T,int>`_, `succ
- <system.html#succ,T,int>`_ and `pred <system.html#pred,T,int>`_ operations can
- fail by raising an `RangeDefect` or `OverflowDefect`. (If the code has been
- compiled with the proper runtime checks turned on.)
- Subranges
- ---------
- A subrange type is a range of values from an integer or enumeration type
- (the base type). Example:
- .. code-block:: nim
- :test: "nim c $1"
- type
- MySubrange = range[0..5]
- `MySubrange` is a subrange of `int` which can only hold the values 0
- to 5. Assigning any other value to a variable of type `MySubrange` is a
- compile-time or runtime error. Assignments from the base type to one of its
- subrange types (and vice versa) are allowed.
- The `system` module defines the important `Natural <system.html#Natural>`_
- type as `range[0..high(int)]` (`high <system.html#high,typedesc[T]>`_ returns
- the maximal value). Other programming languages may suggest the use of unsigned
- integers for natural numbers. This is often **unwise**: you don't want unsigned
- arithmetic (which wraps around) just because the numbers cannot be negative.
- Nim's `Natural` type helps to avoid this common programming error.
- Sets
- ----
- .. include:: sets_fragment.txt
- Arrays
- ------
- An array is a simple fixed-length container. Each element in
- an array has the same type. The array's index type can be any ordinal type.
- Arrays can be constructed using `[]`:
- .. code-block:: nim
- :test: "nim c $1"
- type
- IntArray = array[0..5, int] # an array that is indexed with 0..5
- var
- x: IntArray
- x = [1, 2, 3, 4, 5, 6]
- for i in low(x) .. high(x):
- echo x[i]
- The notation `x[i]` is used to access the i-th element of `x`.
- Array access is always bounds checked (at compile-time or at runtime). These
- checks can be disabled via pragmas or invoking the compiler with the
- ``--bound_checks:off`` command line switch.
- Arrays are value types, like any other Nim type. The assignment operator
- copies the whole array contents.
- The built-in `len <system.html#len,TOpenArray>`_ proc returns the array's
- length. `low(a) <system.html#low,openArray[T]>`_ returns the lowest valid index
- for the array `a` and `high(a) <system.html#high,openArray[T]>`_ the highest
- valid index.
- .. code-block:: nim
- :test: "nim c $1"
- type
- Direction = enum
- north, east, south, west
- BlinkLights = enum
- off, on, slowBlink, mediumBlink, fastBlink
- LevelSetting = array[north..west, BlinkLights]
- var
- level: LevelSetting
- level[north] = on
- level[south] = slowBlink
- level[east] = fastBlink
- echo level # --> [on, fastBlink, slowBlink, off]
- echo low(level) # --> north
- echo len(level) # --> 4
- echo high(level) # --> west
- The syntax for nested arrays (multidimensional) in other languages is a matter
- of appending more brackets because usually each dimension is restricted to the
- same index type as the others. In Nim you can have different dimensions with
- different index types, so the nesting syntax is slightly different. Building on
- the previous example where a level is defined as an array of enums indexed by
- yet another enum, we can add the following lines to add a light tower type
- subdivided into height levels accessed through their integer index:
- .. code-block:: nim
- type
- LightTower = array[1..10, LevelSetting]
- var
- tower: LightTower
- tower[1][north] = slowBlink
- tower[1][east] = mediumBlink
- echo len(tower) # --> 10
- echo len(tower[1]) # --> 4
- echo tower # --> [[slowBlink, mediumBlink, ...more output..
- # The following lines don't compile due to type mismatch errors
- #tower[north][east] = on
- #tower[0][1] = on
- Note how the built-in `len` proc returns only the array's first dimension
- length. Another way of defining the `LightTower` to better illustrate its
- nested nature would be to omit the previous definition of the `LevelSetting`
- type and instead write it embedded directly as the type of the first dimension:
- .. code-block:: nim
- type
- LightTower = array[1..10, array[north..west, BlinkLights]]
- It is quite common to have arrays start at zero, so there's a shortcut syntax
- to specify a range from zero to the specified index minus one:
- .. code-block:: nim
- :test: "nim c $1"
- type
- IntArray = array[0..5, int] # an array that is indexed with 0..5
- QuickArray = array[6, int] # an array that is indexed with 0..5
- var
- x: IntArray
- y: QuickArray
- x = [1, 2, 3, 4, 5, 6]
- y = x
- for i in low(x) .. high(x):
- echo x[i], y[i]
- Sequences
- ---------
- Sequences are similar to arrays but of dynamic length which may change
- during runtime (like strings). Since sequences are resizable they are always
- allocated on the heap and garbage collected.
- Sequences are always indexed with an `int` starting at position 0. The `len
- <system.html#len,seq[T]>`_, `low <system.html#low,openArray[T]>`_ and `high
- <system.html#high,openArray[T]>`_ operations are available for sequences too.
- The notation `x[i]` can be used to access the i-th element of `x`.
- Sequences can be constructed by the array constructor `[]` in conjunction
- with the array to sequence operator `@`. Another way to allocate space for
- a sequence is to call the built-in `newSeq <system.html#newSeq>`_ procedure.
- A sequence may be passed to an openarray parameter.
- Example:
- .. code-block:: nim
- :test: "nim c $1"
- var
- x: seq[int] # a reference to a sequence of integers
- x = @[1, 2, 3, 4, 5, 6] # the @ turns the array into a sequence allocated on the heap
- Sequence variables are initialized with `@[]`.
- The `for` statement can be used with one or two variables when used with a
- sequence. When you use the one variable form, the variable will hold the value
- provided by the sequence. The `for` statement is looping over the results
- from the `items() <iterators.html#items.i,seq[T]>`_ iterator from the `system
- <system.html>`_ module. But if you use the two-variable form, the first
- variable will hold the index position and the second variable will hold the
- value. Here the `for` statement is looping over the results from the
- `pairs() <iterators.html#pairs.i,seq[T]>`_ iterator from the `system
- <system.html>`_ module. Examples:
- .. code-block:: nim
- :test: "nim c $1"
- for value in @[3, 4, 5]:
- echo value
- # --> 3
- # --> 4
- # --> 5
- for i, value in @[3, 4, 5]:
- echo "index: ", $i, ", value:", $value
- # --> index: 0, value:3
- # --> index: 1, value:4
- # --> index: 2, value:5
- Open arrays
- -----------
- **Note**: Openarrays can only be used for parameters.
- Often fixed-size arrays turn out to be too inflexible; procedures should be
- able to deal with arrays of different sizes. The `openarray`:idx: type allows
- this. Openarrays are always indexed with an `int` starting at position 0.
- The `len <system.html#len,TOpenArray>`_, `low <system.html#low,openArray[T]>`_
- and `high <system.html#high,openArray[T]>`_ operations are available for open
- arrays too. Any array with a compatible base type can be passed to an
- openarray parameter, the index type does not matter.
- .. code-block:: nim
- :test: "nim c $1"
- var
- fruits: seq[string] # reference to a sequence of strings that is initialized with '@[]'
- capitals: array[3, string] # array of strings with a fixed size
- capitals = ["New York", "London", "Berlin"] # array 'capitals' allows assignment of only three elements
- fruits.add("Banana") # sequence 'fruits' is dynamically expandable during runtime
- fruits.add("Mango")
- proc openArraySize(oa: openArray[string]): int =
- oa.len
- assert openArraySize(fruits) == 2 # procedure accepts a sequence as parameter
- assert openArraySize(capitals) == 3 # but also an array type
- The openarray type cannot be nested: multidimensional openarrays are not
- supported because this is seldom needed and cannot be done efficiently.
- Varargs
- -------
- A `varargs` parameter is like an openarray parameter. However, it is
- also a means to implement passing a variable number of
- arguments to a procedure. The compiler converts the list of arguments
- to an array automatically:
- .. code-block:: nim
- :test: "nim c $1"
- proc myWriteln(f: File, a: varargs[string]) =
- for s in items(a):
- write(f, s)
- write(f, "\n")
- myWriteln(stdout, "abc", "def", "xyz")
- # is transformed by the compiler to:
- myWriteln(stdout, ["abc", "def", "xyz"])
- This transformation is only done if the varargs parameter is the
- last parameter in the procedure header. It is also possible to perform
- type conversions in this context:
- .. code-block:: nim
- :test: "nim c $1"
- proc myWriteln(f: File, a: varargs[string, `$`]) =
- for s in items(a):
- write(f, s)
- write(f, "\n")
- myWriteln(stdout, 123, "abc", 4.0)
- # is transformed by the compiler to:
- myWriteln(stdout, [$123, $"abc", $4.0])
- In this example `$ <dollars.html>`_ is applied to any argument that is passed
- to the parameter `a`. Note that `$ <dollars.html>`_ applied to strings is a
- nop.
- Slices
- ------
- Slices look similar to subranges types in syntax but are used in a different
- context. A slice is just an object of type Slice which contains two bounds,
- `a` and `b`. By itself a slice is not very useful, but other collection types
- define operators which accept Slice objects to define ranges.
- .. code-block:: nim
- :test: "nim c $1"
- var
- a = "Nim is a programming language"
- b = "Slices are useless."
- echo a[7 .. 12] # --> 'a prog'
- b[11 .. ^2] = "useful"
- echo b # --> 'Slices are useful.'
- In the previous example slices are used to modify a part of a string. The
- slice's bounds can hold any value supported by
- their type, but it is the proc using the slice object which defines what values
- are accepted.
- To understand some of the different ways of specifying the indices of
- strings, arrays, sequences, etc., it must be remembered that Nim uses
- zero-based indices.
- So the string `b` is of length 19, and two different ways of specifying the
- indices are
- .. code-block:: nim
- "Slices are useless."
- | | |
- 0 11 17 using indices
- ^19 ^8 ^2 using ^ syntax
- where `b[0 .. ^1]` is equivalent to `b[0 .. b.len-1]` and `b[0 ..< b.len]`, and it
- can be seen that the `^1` provides a short-hand way of specifying the `b.len-1`. See
- the `backwards index operator <system.html#^.t%2Cint>`_.
- In the above example, because the string ends in a period, to get the portion of the
- string that is "useless" and replace it with "useful".
- `b[11 .. ^2]` is the portion "useless", and `b[11 .. ^2] = "useful"` replaces the
- "useless" portion with "useful", giving the result "Slices are useful."
- Note 1: alternate ways of writing this are `b[^8 .. ^2] = "useful"` or
- as `b[11 .. b.len-2] = "useful"` or as `b[11 ..< b.len-1] = "useful"`.
- Note 2: As the `^` template returns a `distinct int <manual.html#types-distinct-type>`_
- of type `BackwardsIndex`, we can have a `lastIndex` constant defined as `const lastIndex = ^1`,
- and later used as `b[0 .. lastIndex]`.
- Objects
- -------
- The default type to pack different values together in a single
- structure with a name is the object type. An object is a value type,
- which means that when an object is assigned to a new variable all its
- components are copied as well.
- Each object type `Foo` has a constructor `Foo(field: value, ...)`
- where all of its fields can be initialized. Unspecified fields will
- get their default value.
- .. code-block:: nim
- type
- Person = object
- name: string
- age: int
- var person1 = Person(name: "Peter", age: 30)
- echo person1.name # "Peter"
- echo person1.age # 30
- var person2 = person1 # copy of person 1
- person2.age += 14
- echo person1.age # 30
- echo person2.age # 44
- # the order may be changed
- let person3 = Person(age: 12, name: "Quentin")
- # not every member needs to be specified
- let person4 = Person(age: 3)
- # unspecified members will be initialized with their default
- # values. In this case it is the empty string.
- doAssert person4.name == ""
- Object fields that should be visible from outside the defining module have to
- be marked with `*`.
- .. code-block:: nim
- :test: "nim c $1"
- type
- Person* = object # the type is visible from other modules
- name*: string # the field of this type is visible from other modules
- age*: int
- Tuples
- ------
- Tuples are very much like what you have seen so far from objects. They
- are value types where the assignment operator copies each component.
- Unlike object types though, tuple types are structurally typed,
- meaning different tuple-types are *equivalent* if they specify fields of
- the same type and of the same name in the same order.
- The constructor `()` can be used to construct tuples. The order of the
- fields in the constructor must match the order in the tuple's
- definition. But unlike objects, a name for the tuple type may not be
- used here.
- Like the object type the notation `t.field` is used to access a
- tuple's field. Another notation that is not available for objects is
- `t[i]` to access the `i`'th field. Here `i` must be a constant
- integer.
- .. code-block:: nim
- :test: "nim c $1"
- type
- # type representing a person:
- # A person consists of a name and an age.
- Person = tuple
- name: string
- age: int
- # Alternative syntax for an equivalent type.
- PersonX = tuple[name: string, age: int]
- # anonymous field syntax
- PersonY = (string, int)
- var
- person: Person
- personX: PersonX
- personY: PersonY
- person = (name: "Peter", age: 30)
- # Person and PersonX are equivalent
- personX = person
- # Create a tuple with anonymous fields:
- personY = ("Peter", 30)
- # A tuple with anonymous fields is compatible with a tuple that has
- # field names.
- person = personY
- personY = person
- # Usually used for short tuple initialization syntax
- person = ("Peter", 30)
- echo person.name # "Peter"
- echo person.age # 30
- echo person[0] # "Peter"
- echo person[1] # 30
- # You don't need to declare tuples in a separate type section.
- var building: tuple[street: string, number: int]
- building = ("Rue del Percebe", 13)
- echo building.street
- # The following line does not compile, they are different tuples!
- #person = building
- # --> Error: type mismatch: got (tuple[street: string, number: int])
- # but expected 'Person'
- Even though you don't need to declare a type for a tuple to use it, tuples
- created with different field names will be considered different objects despite
- having the same field types.
- Tuples can be *unpacked* during variable assignment. This can
- be handy to assign directly the fields of the tuples to individually named
- variables. An example of this is the `splitFile <os.html#splitFile,string>`_
- proc from the `os module <os.html>`_ which returns the directory, name, and
- extension of a path at the same time. For tuple unpacking to work you must
- use parentheses around the values you want to assign the unpacking to,
- otherwise, you will be assigning the same value to all the individual
- variables! For example:
- .. code-block:: nim
- :test: "nim c $1"
- import std/os
- let
- path = "usr/local/nimc.html"
- (dir, name, ext) = splitFile(path)
- baddir, badname, badext = splitFile(path)
- echo dir # outputs "usr/local"
- echo name # outputs "nimc"
- echo ext # outputs ".html"
- # All the following output the same line:
- # "(dir: usr/local, name: nimc, ext: .html)"
- echo baddir
- echo badname
- echo badext
- Fields of tuples are always public, they don't need to be explicity
- marked to be exported, unlike for example fields in an object type.
- Reference and pointer types
- ---------------------------
- References (similar to pointers in other programming languages) are a
- way to introduce many-to-one relationships. This means different references can
- point to and modify the same location in memory.
- Nim distinguishes between `traced`:idx: and `untraced`:idx: references.
- Untraced references are also called *pointers*. Traced references point to
- objects in a garbage-collected heap, untraced references point to
- manually allocated objects or objects elsewhere in memory. Thus
- untraced references are *unsafe*. However, for certain low-level operations
- (e.g. accessing the hardware), untraced references are necessary.
- Traced references are declared with the **ref** keyword; untraced references
- are declared with the **ptr** keyword.
- The empty `[]` subscript notation can be used to *de-refer* a reference,
- meaning to retrieve the item the reference points to. The `.` (access a
- tuple/object field operator) and `[]` (array/string/sequence index operator)
- operators perform implicit dereferencing operations for reference types:
- .. code-block:: nim
- :test: "nim c $1"
- type
- Node = ref object
- le, ri: Node
- data: int
- var
- n: Node
- new(n)
- n.data = 9
- # no need to write n[].data; in fact n[].data is highly discouraged!
- To allocate a new traced object, the built-in procedure `new` must be used.
- To deal with untraced memory, the procedures `alloc`, `dealloc` and
- `realloc` can be used. The `system <system.html>`_
- module's documentation contains further details.
- If a reference points to *nothing*, it has the value `nil`.
- Procedural type
- ---------------
- A procedural type is a (somewhat abstract) pointer to a procedure.
- `nil` is an allowed value for a variable of a procedural type.
- Nim uses procedural types to achieve `functional`:idx: programming
- techniques.
- Example:
- .. code-block:: nim
- :test: "nim c $1"
- proc echoItem(x: int) = echo x
- proc forEach(action: proc (x: int)) =
- const
- data = [2, 3, 5, 7, 11]
- for d in items(data):
- action(d)
- forEach(echoItem)
- A subtle issue with procedural types is that the calling convention of the
- procedure influences the type compatibility: procedural types are only compatible
- if they have the same calling convention. The different calling conventions are
- listed in the `manual <manual.html#types-procedural-type>`_.
- Distinct type
- -------------
- A Distinct type allows for the creation of a new type that "does not imply a
- subtype relationship between it and its base type".
- You must **explicitly** define all behavior for the distinct type.
- To help with this, both the distinct type and its base type can cast from one
- type to the other.
- Examples are provided in the `manual <manual.html#types-distinct-type>`_.
- Modules
- =======
- Nim supports splitting a program into pieces with a *module* concept.
- Each module is in its own file. Modules enable `information hiding`:idx: and
- `separate compilation`:idx:. A module may gain access to the symbols of another
- module by using the `import`:idx: statement. Only top-level symbols that are marked
- with an asterisk (`*`) are exported:
- .. code-block:: nim
- # Module A
- var
- x*, y: int
- proc `*` *(a, b: seq[int]): seq[int] =
- # allocate a new sequence:
- newSeq(result, len(a))
- # multiply two int sequences:
- for i in 0 ..< len(a): result[i] = a[i] * b[i]
- when isMainModule:
- # test the new `*` operator for sequences:
- assert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9])
- The above module exports `x` and `*`, but not `y`.
- A module's top-level statements are executed at the start of the program.
- This can be used to initialize complex data structures for example.
- Each module has a special magic constant `isMainModule` that is true if the
- module is compiled as the main file. This is very useful to embed tests within
- the module as shown by the above example.
- A symbol of a module *can* be *qualified* with the `module.symbol` syntax. And if
- a symbol is ambiguous, it *must* be qualified. A symbol is ambiguous
- if it is defined in two (or more) different modules and both modules are
- imported by a third one:
- .. code-block:: nim
- # Module A
- var x*: string
- .. code-block:: nim
- # Module B
- var x*: int
- .. code-block:: nim
- # Module C
- import A, B
- write(stdout, x) # error: x is ambiguous
- write(stdout, A.x) # okay: qualifier used
- var x = 4
- write(stdout, x) # not ambiguous: uses the module C's x
- But this rule does not apply to procedures or iterators. Here the overloading
- rules apply:
- .. code-block:: nim
- # Module A
- proc x*(a: int): string = $a
- .. code-block:: nim
- # Module B
- proc x*(a: string): string = $a
- .. code-block:: nim
- # Module C
- import A, B
- write(stdout, x(3)) # no error: A.x is called
- write(stdout, x("")) # no error: B.x is called
- proc x*(a: int): string = discard
- write(stdout, x(3)) # ambiguous: which `x` is to call?
- Excluding symbols
- -----------------
- The normal `import` statement will bring in all exported symbols.
- These can be limited by naming symbols that should be excluded using
- the `except` qualifier.
- .. code-block:: nim
- import mymodule except y
- From statement
- --------------
- We have already seen the simple `import` statement that just imports all
- exported symbols. An alternative that only imports listed symbols is the
- `from import` statement:
- .. code-block:: nim
- from mymodule import x, y, z
- The `from` statement can also force namespace qualification on
- symbols, thereby making symbols available, but needing to be qualified
- in order to be used.
- .. code-block:: nim
- from mymodule import x, y, z
- x() # use x without any qualification
- .. code-block:: nim
- from mymodule import nil
- mymodule.x() # must qualify x with the module name as prefix
- x() # using x here without qualification is a compile error
- Since module names are generally long to be descriptive, you can also
- define a shorter alias to use when qualifying symbols.
- .. code-block:: nim
- from mymodule as m import nil
- m.x() # m is aliasing mymodule
- Include statement
- -----------------
- The `include` statement does something fundamentally different than
- importing a module: it merely includes the contents of a file. The `include`
- statement is useful to split up a large module into several files:
- .. code-block:: nim
- include fileA, fileB, fileC
- Part 2
- ======
- So, now that we are done with the basics, let's see what Nim offers apart
- from a nice syntax for procedural programming: `Part II <tut2.html>`_
- .. _strutils: strutils.html
- .. _system: system.html
|