diff options
Diffstat (limited to 'doc/tut1.md')
-rw-r--r-- | doc/tut1.md | 1952 |
1 files changed, 1952 insertions, 0 deletions
diff --git a/doc/tut1.md b/doc/tut1.md new file mode 100644 index 000000000..2e83effa3 --- /dev/null +++ b/doc/tut1.md @@ -0,0 +1,1952 @@ +===================== +Nim Tutorial (Part I) +===================== + +:Author: Andreas Rumpf +:Version: |nimversion| + +.. default-role:: code +.. include:: rstcommon.rst +.. contents:: + +Introduction +============ + +> "Der Mensch ist doch ein Augentier -- Schöne Dinge wünsch' ich mir." + + +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: + + ```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: + ```cmd + 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: + ```cmd + nim compile --run greetings.nim arg1 arg2 + ``` + +Commonly used commands and switches have abbreviations, so you can also use: + ```cmd + nim c -r greetings.nim + ``` + +This is a **debug version**. +To compile a release version use: + ```cmd + 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](syncio.html#readLine,File) procedure. Since the +compiler knows that [readLine](syncio.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: + + ```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](syncio.html#readLine,File), etc. +These built-ins are declared in the [system](system.html) 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: + + ```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 `##`: + + ```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. + + ```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: + + ```nim + 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: + + ```nim 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: + + ```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: + + ```nim 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: + + ```nim + 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": + + ```nim + const input = readLine(stdin) # Error: constant expression expected + ``` + + ```nim 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: + + ```nim + 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: + + ```nim 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: + + ```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 allows +for multiple branches: + + ```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: + + ```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: + + ```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] 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: + + ```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: + + ```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: + + ```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: + + ```nim + for i in 1 .. 10: + ... + ``` + +Counting down can be achieved as easily (but is less often needed): + + ```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: + + ```nim + for i in 0 ..< 10: + ... # the same as 0 .. 9 + ``` + +or + + ```nim + var s = "some string" + for i in 0 ..< s.len: + ... + ``` + +or + + ```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) + + ```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: + + ```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: + + ```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: + + ```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: + + ```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: + + ```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: + + ```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: + + ```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: + + ```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](syncio.html#readLine,File) in the examples, the concept of a +*procedure* is needed. You might be used to them being called *methods* or +*functions* in other languages, but Nim +[differentiates these concepts](tut1.html#procedures-funcs-and-methods). In +Nim, new procedures are defined with the `proc` keyword: + + ```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. + + ```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 + + ```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: + + ```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: + + ```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: + + ```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: + + ```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: + + ```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: + + ```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: + + ```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++: + + ```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 "`": + + ```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: + + ```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: + + ```nim + # forward declaration: + proc even(n: int): bool + ``` + + ```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. + + +Funcs and methods +----------------- + +As mentioned in the introduction, Nim differentiates between procedures, +functions, and methods, defined by the `proc`, `func`, and `method` keywords +respectively. In some ways, Nim is a bit more pedantic in its definitions than +other languages. + +Functions are closer to the concept of a pure mathematical +function, which might be familiar to you if you've ever done functional +programming. Essentially they are procedures with additional limitations set on +them: they can't access global state (except `const`) and can't produce +side-effects. The `func` keyword is basically an alias for `proc` tagged +with `{.noSideEffects.}`. Functions can still change their mutable arguments +however, which are those marked as `var`, along with any `ref` objects. + +Unlike procedures, methods are dynamically dispatched. This sounds a bit +complicated, but it is a concept closely related to inheritance and object-oriented +programming. If you overload a procedure (two procedures with the same name but +of different types or with different sets of arguments are said to be overloaded), the procedure to use is determined +at compile-time. Methods, on the other hand, depend on objects that inherit from +the `RootObj`. This is something that is covered in much greater depth in +the [second part of the tutorial](tut2.html#object-oriented-programming-dynamic-dispatch). + + +Iterators +========= + +Let's return to the simple counting example: + + ```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? Let's try: + + ```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: + + ```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 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: + + ```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 multibyte 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: + + + ```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: + + ```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: + + ```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: + + ```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: + + ```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: + + ```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: + + ```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 `[]`: + + ```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. + + ```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: + + ```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: + + ```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: + + ```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: + + ```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: + + ```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. + + ```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: + + ```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: + + ```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. + + ```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 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 + + ```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 shorthand 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. + + ```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 `*`. + + ```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. + + ```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: + + ```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 + ``` + +Tuple unpacking is also supported in for-loops: + + ```nim test = "nim c $1" + let a = [(10, 'a'), (20, 'b'), (30, 'c')] + + for (x, c) in a: + echo x + # This will output: 10; 20; 30 + + # Accessing the index is also possible: + for i, (x, c) in a: + echo i, c + # This will output: 0a; 1b; 2c + ``` + +Fields of tuples are always public, they don't need to be explicitly +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: + + ```nim test = "nim c $1" + type + Node = ref object + le, ri: Node + data: int + + var n = Node(data: 9) + echo n.data + # no need to write n[].data; in fact n[].data is highly discouraged! + ``` + +To allocate a new traced object, the built-in procedure `new` can be used: + + ```nim + var n: Node + new(n) + ``` + +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: + + ```nim test = "nim c $1" + proc greet(name: string): string = + "Hello, " & name & "!" + + proc bye(name: string): string = + "Goodbye, " & name & "." + + proc communicate(greeting: proc (x: string): string, name: string) = + echo greeting(name) + + communicate(greet, "John") + communicate(bye, "Mary") + ``` + +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: + + ```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: + + ```nim + # Module A + var x*: string + ``` + + ```nim + # Module B + var x*: int + ``` + + ```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: + + ```nim + # Module A + proc x*(a: int): string = $a + ``` + + ```nim + # Module B + proc x*(a: string): string = $a + ``` + + ```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. + + ```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: + + ```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. + + ```nim + from mymodule import x, y, z + + x() # use x without any qualification + ``` + + ```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. + + ```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: + + ```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 |