small improvements for tut1.rst (#17935)

* small improvements for tut1.rst
* remove unneeded paragraph
* Update doc/tut1.rst

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
This commit is contained in:
Miran
2021-05-05 07:44:33 +02:00
committed by GitHub
parent 15d9566952
commit 94c4c01d9c
2 changed files with 101 additions and 79 deletions

View File

@@ -17,6 +17,9 @@ Attempting to declare a set with a larger type will result in an error:
var s: set[int64] # Error: set is too large
**Note:** Nim also offers `hash sets <sets.html>`_ (which you need to import
with `import sets`), which have no such restrictions.
Sets can be constructed via the set constructor: `{}` is the empty set. The
empty set is type compatible with any concrete set type. The constructor
can also be used to include elements (and ranges of elements):

View File

@@ -22,10 +22,14 @@ 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.
If you would like to have a gentle introduction of those concepts, we recommend
`Nim Basics tutorial <https://narimiran.github.io/nim-basics/>`_.
On the other hand, the `manual <manual.html>`_ contains many more examples of
the advanced language features.
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>`_.
@@ -58,6 +62,7 @@ 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
@@ -119,7 +124,7 @@ 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
multiple lines and the ``\`` is not an escape character either. They are very
useful for embedding HTML code templates for example.
@@ -184,37 +189,6 @@ variables:
a, b, c: string
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"
Note that declaring multiple variables with a single assignment that calls a
procedure can have unexpected results: the compiler will *unroll* the
assignments and end up calling the procedure several times. If the result of
the procedure depends on side effects, your variables may end up having
different values! For safety use side-effect-free procedures if making multiple
assignments.
Constants
=========
@@ -260,6 +234,30 @@ and put it into a data section":
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
=======================
@@ -325,7 +323,7 @@ For integers or other ordinal types value ranges are also possible:
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
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
@@ -361,8 +359,7 @@ The while statement is a simple looping construct:
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
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).
@@ -392,9 +389,16 @@ The variable `i` is implicitly declared by the
var i = 1
while i <= 10:
echo i
inc(i) # increment i by 1
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
@@ -403,20 +407,13 @@ Counting down can be achieved as easily (but is less often needed):
echo i
# --> Outputs 10 9 8 7 6 5 4 3 2 1 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:
...
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:
... # 0 .. 9
... # the same as 0 .. 9
or
@@ -430,7 +427,7 @@ 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
@@ -445,6 +442,7 @@ Other useful iterators for collections (like arrays and sequences) are
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:
@@ -472,6 +470,7 @@ 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:
@@ -497,15 +496,15 @@ innermost construct, unless a label of a block is given:
Continue statement
------------------
Like in many other programming languages, a `continue` statement starts
the next iteration immediately:
.. code-block:: nim
:test: "nim c $1"
while true:
let x = readLine(stdin)
if x == "": continue
echo x
for i in 1 .. 5:
if i <= 3: continue
echo i # will only print 4 and 5
When statement
@@ -630,6 +629,7 @@ Some terminology: in the example `question` is called a (formal) *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
@@ -644,9 +644,9 @@ the exit.
return
result = result + i
echo sumTillNegative() # echos 0
echo sumTillNegative(3, 4, 5) # echos 12
echo sumTillNegative(3, 4 , -1 , 6) # echos 7
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
@@ -662,12 +662,13 @@ this procedure
.. code-block:: nim
:test: "nim c $1"
proc helloWorld(): string =
"Hello, World!"
"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
@@ -704,6 +705,7 @@ 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:
@@ -752,6 +754,7 @@ 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:
@@ -773,6 +776,7 @@ no need to write `title: string = "unknown"`, for example.
Overloaded procedures
---------------------
Nim provides the ability to overload procedures similar to C++:
.. code-block:: nim
@@ -793,14 +797,13 @@ Nim provides the ability to overload procedures similar to C++:
(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 (it will be specified in the manual soon). However, it does
not lead to nasty surprises and is based on a quite simple unification
algorithm. Ambiguous calls are reported as errors.
discussed here -- see the manual for details. Ambiguous calls are reported as errors.
Operators
---------
The Nim library makes heavy use of overloading - one reason for this is that
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.
@@ -816,7 +819,7 @@ 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.
can be `found in the manual <manual.html#syntax-precedence>`_.
To define a new operator enclose the operator in backticks "`":
@@ -830,7 +833,7 @@ procedure:
.. code-block:: nim
:test: "nim c $1"
if `==`( `+`(3, 4), 7): echo "True"
if `==`( `+`(3, 4), 7): echo "true"
Forward declarations
@@ -896,7 +899,7 @@ 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:
and here it is -- our first iterator:
.. code-block:: nim
:test: "nim c $1"
@@ -914,10 +917,10 @@ important differences:
`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.)
* 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
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
@@ -952,6 +955,7 @@ evaluation. For example:
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.
@@ -968,6 +972,7 @@ 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`
@@ -989,6 +994,7 @@ 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`.
@@ -1001,7 +1007,7 @@ to specify a non-default integer type:
let
x = 0 # x is of type `int`
y = 0'i8 # y is of type `int8`
z = 0'i64 # z is of type `int64`
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
@@ -1019,12 +1025,13 @@ 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 `EOutOfRange`:idx: exception is raised (if the error
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,
@@ -1051,6 +1058,7 @@ versa. Use the `toInt <system.html#toInt,float>`_ and
Type Conversion
---------------
Conversion between numerical types is performed by using the
type as a function:
@@ -1093,7 +1101,7 @@ there is a difference between the `$` and `repr` outputs:
echo myInteger, ":", repr(myInteger)
# --> 42:42
echo myFloat, ":", repr(myFloat)
# --> 3.1400000000000001e+00:3.1400000000000001e+00
# --> 3.14:3.14
Advanced types
@@ -1113,6 +1121,7 @@ Enumeration and object types may only be defined within a
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
@@ -1126,7 +1135,7 @@ at runtime by 0, the second by 1, and so on. For example:
north, east, south, west
var x = south # `x` is of type `Direction`; its value is `south`
echo x # writes "south" to `stdout`
echo x # prints "south"
All the comparison operators can be used with enumeration types.
@@ -1143,6 +1152,7 @@ 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:
@@ -1166,12 +1176,13 @@ Operation Comment
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 `EOutOfRange` or `EOverflow` exception. (If the code has been
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:
@@ -1201,6 +1212,7 @@ Sets
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.
@@ -1214,7 +1226,7 @@ Arrays can be constructed using `[]`:
var
x: IntArray
x = [1, 2, 3, 4, 5, 6]
for i in low(x)..high(x):
for i in low(x) .. high(x):
echo x[i]
The notation `x[i]` is used to access the i-th element of `x`.
@@ -1243,7 +1255,7 @@ valid index.
level[north] = on
level[south] = slowBlink
level[east] = fastBlink
echo repr(level) # --> [on, fastBlink, slowBlink, off]
echo level # --> [on, fastBlink, slowBlink, off]
echo low(level) # --> north
echo len(level) # --> 4
echo high(level) # --> west
@@ -1265,7 +1277,7 @@ subdivided into height levels accessed through their integer index:
tower[1][east] = mediumBlink
echo len(tower) # --> 10
echo len(tower[1]) # --> 4
echo repr(tower) # --> [[slowBlink, mediumBlink, ...more output..
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
@@ -1292,12 +1304,13 @@ to specify a range from zero to the specified index minus one:
y: QuickArray
x = [1, 2, 3, 4, 5, 6]
y = x
for i in low(x)..high(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.
@@ -1351,6 +1364,7 @@ value. Here the `for` statement is looping over the results from the
Open arrays
-----------
**Note**: Openarrays can only be used for parameters.
Often fixed-size arrays turn out to be too inflexible; procedures should be
@@ -1602,7 +1616,7 @@ 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 (and only then!). This can
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
@@ -1634,6 +1648,7 @@ 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.
@@ -1643,7 +1658,7 @@ 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.
(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.
@@ -1676,6 +1691,7 @@ 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
@@ -1702,6 +1718,7 @@ 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.
@@ -1711,6 +1728,7 @@ 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
@@ -1726,7 +1744,7 @@ with an asterisk (`*`) are exported:
# allocate a new sequence:
newSeq(result, len(a))
# multiply two int sequences:
for i in 0..len(a)-1: result[i] = a[i] * b[i]
for i in 0 ..< len(a): result[i] = a[i] * b[i]
when isMainModule:
# test the new `*` operator for sequences:
@@ -1833,6 +1851,7 @@ define a shorter alias to use when qualifying symbols.
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: