manual split up into multiple files; documented the new concurrency system
This commit is contained in:
parent
e9dec2feed
commit
2c1f3f75f5
31 changed files with 6198 additions and 5901 deletions
185
doc/manual/modules.txt
Normal file
185
doc/manual/modules.txt
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
Modules
|
||||
=======
|
||||
Nim supports splitting a program into pieces by a module concept.
|
||||
Each module needs to be in its own file and has its own `namespace`:idx:.
|
||||
Modules enable `information hiding`:idx: and `separate compilation`:idx:.
|
||||
A module may gain access to symbols of another module by the `import`:idx:
|
||||
statement. `Recursive module dependencies`:idx: are allowed, but slightly
|
||||
subtle. Only top-level symbols that are marked with an asterisk (``*``) are
|
||||
exported.
|
||||
|
||||
The algorithm for compiling modules is:
|
||||
|
||||
- compile the whole module as usual, following import statements recursively
|
||||
|
||||
- if there is a cycle only import the already parsed symbols (that are
|
||||
exported); if an unknown identifier occurs then abort
|
||||
|
||||
This is best illustrated by an example:
|
||||
|
||||
.. code-block:: nim
|
||||
# Module A
|
||||
type
|
||||
T1* = int # Module A exports the type ``T1``
|
||||
import B # the compiler starts parsing B
|
||||
|
||||
proc main() =
|
||||
var i = p(3) # works because B has been parsed completely here
|
||||
|
||||
main()
|
||||
|
||||
|
||||
.. code-block:: nim
|
||||
# Module B
|
||||
import A # A is not parsed here! Only the already known symbols
|
||||
# of A are imported.
|
||||
|
||||
proc p*(x: A.T1): A.T1 =
|
||||
# this works because the compiler has already
|
||||
# added T1 to A's interface symbol table
|
||||
result = x + 1
|
||||
|
||||
|
||||
Import statement
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
After the ``import`` statement a list of module names can follow or a single
|
||||
module name followed by an ``except`` to prevent some symbols to be imported:
|
||||
|
||||
.. code-block:: nim
|
||||
import strutils except `%`
|
||||
|
||||
# doesn't work then:
|
||||
echo "$1" % "abc"
|
||||
|
||||
|
||||
Module names in imports
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A module alias can be introduced via the ``as`` keyword:
|
||||
|
||||
.. code-block:: nim
|
||||
import strutils as su, sequtils as qu
|
||||
|
||||
echo su.format("$1", "lalelu")
|
||||
|
||||
The original module name is then not accessible. The
|
||||
notations ``path/to/module`` or ``path.to.module`` or ``"path/to/module"``
|
||||
can be used to refer to a module in subdirectories:
|
||||
|
||||
.. code-block:: nim
|
||||
import lib.pure.strutils, lib/pure/os, "lib/pure/times"
|
||||
|
||||
Note that the module name is still ``strutils`` and not ``lib.pure.strutils``
|
||||
and so one **cannot** do:
|
||||
|
||||
.. code-block:: nim
|
||||
import lib.pure.strutils
|
||||
echo lib.pure.strutils
|
||||
|
||||
Likewise the following does not make sense as the name is ``strutils`` already:
|
||||
|
||||
.. code-block:: nim
|
||||
import lib.pure.strutils as strutils
|
||||
|
||||
|
||||
From import statement
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
After the ``from`` statement a module name follows followed by
|
||||
an ``import`` to list the symbols one likes to use without explict
|
||||
full qualification:
|
||||
|
||||
.. code-block:: nim
|
||||
from strutils import `%`
|
||||
|
||||
echo "$1" % "abc"
|
||||
# always possible: full qualification:
|
||||
echo strutils.replace("abc", "a", "z")
|
||||
|
||||
It's also possible to use ``from module import nil`` if one wants to import
|
||||
the module but wants to enforce fully qualified access to every symbol
|
||||
in ``module``.
|
||||
|
||||
|
||||
Export statement
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
An ``export`` statement can be used for symbol fowarding so that client
|
||||
modules don't need to import a module's dependencies:
|
||||
|
||||
.. code-block:: nim
|
||||
# module B
|
||||
type TMyObject* = object
|
||||
|
||||
.. code-block:: nim
|
||||
# module A
|
||||
import B
|
||||
export B.TMyObject
|
||||
|
||||
proc `$`*(x: TMyObject): string = "my object"
|
||||
|
||||
|
||||
.. code-block:: nim
|
||||
# module C
|
||||
import A
|
||||
|
||||
# B.TMyObject has been imported implicitly here:
|
||||
var x: TMyObject
|
||||
echo($x)
|
||||
|
||||
|
||||
Scope rules
|
||||
-----------
|
||||
Identifiers are valid from the point of their declaration until the end of
|
||||
the block in which the declaration occurred. The range where the identifier
|
||||
is known is the scope of the identifier. The exact scope of an
|
||||
identifier depends on the way it was declared.
|
||||
|
||||
Block scope
|
||||
~~~~~~~~~~~
|
||||
The *scope* of a variable declared in the declaration part of a block
|
||||
is valid from the point of declaration until the end of the block. If a
|
||||
block contains a second block, in which the identifier is redeclared,
|
||||
then inside this block, the second declaration will be valid. Upon
|
||||
leaving the inner block, the first declaration is valid again. An
|
||||
identifier cannot be redefined in the same block, except if valid for
|
||||
procedure or iterator overloading purposes.
|
||||
|
||||
|
||||
Tuple or object scope
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
The field identifiers inside a tuple or object definition are valid in the
|
||||
following places:
|
||||
|
||||
* To the end of the tuple/object definition.
|
||||
* Field designators of a variable of the given tuple/object type.
|
||||
* In all descendant types of the object type.
|
||||
|
||||
Module scope
|
||||
~~~~~~~~~~~~
|
||||
All identifiers of a module are valid from the point of declaration until
|
||||
the end of the module. Identifiers from indirectly dependent modules are *not*
|
||||
available. The `system`:idx: module is automatically imported in every other
|
||||
module.
|
||||
|
||||
If a module imports an identifier by two different modules, each occurrence of
|
||||
the identifier has to be qualified, unless it is an overloaded procedure or
|
||||
iterator in which case the overloading resolution takes place:
|
||||
|
||||
.. 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) # no error: qualifier used
|
||||
|
||||
var x = 4
|
||||
write(stdout, x) # not ambiguous: uses the module C's x
|
||||
Loading…
Add table
Add a link
Reference in a new issue