diff options
author | Zahary Karadjov <zahary@gmail.com> | 2012-09-27 22:44:32 +0300 |
---|---|---|
committer | Zahary Karadjov <zahary@gmail.com> | 2012-09-27 22:44:52 +0300 |
commit | 88ea9073c371c7bc43035a0c756d3ded4b83e0aa (patch) | |
tree | 2aaf6378ac25fbe8a87aaf0466ff74e3dd9fcf5d /doc | |
parent | 04c5f58ce4a5c41e1b3ec758479bd58c6b2f33ae (diff) | |
download | Nim-88ea9073c371c7bc43035a0c756d3ded4b83e0aa.tar.gz |
missing documentation added to the manual
documented: * closures and the do notation * type classes * return type inference * typedesc parameters and values * destructor pragma * fixed a number of typos
Diffstat (limited to 'doc')
-rwxr-xr-x | doc/manual.txt | 286 |
1 files changed, 248 insertions, 38 deletions
diff --git a/doc/manual.txt b/doc/manual.txt index e9eb3871a..4b7dc1aa5 100755 --- a/doc/manual.txt +++ b/doc/manual.txt @@ -2,7 +2,7 @@ Nimrod Manual ============= -:Author: Andreas Rumpf +:Authors: Andreas Rumpf, Zahary Karadjov :Version: |nimrodversion| .. contents:: @@ -780,7 +780,7 @@ and ``pred`` are not available for them either. The compiler supports the built-in stringify operator ``$`` for enumerations. -The stringify's result can be controlled by explicitely giving the string +The stringify's result can be controlled by explicitly giving the string values to use: .. code-block:: nimrod @@ -845,9 +845,9 @@ interfacing with C. The index operation ``s[i]`` means the i-th *char* of ``s``; however no bounds checking for ``cstring`` is performed making the index operation unsafe. -A Nimrod ``string`` is implicitely convertible +A Nimrod ``string`` is implicitly convertible to ``cstring`` for convenience. If a Nimrod string is passed to a C-style -variadic proc, it is implicitely converted to ``cstring`` too: +variadic proc, it is implicitly converted to ``cstring`` too: .. code-block:: nimrod proc printf(formatstr: cstring) {.importc: "printf", varargs, @@ -922,7 +922,7 @@ Varargs A `varargs`:idx: parameter is an openarray parameter that additionally allows to pass a variable number of arguments to a procedure. The compiler -converts the list of arguments to an array implicitely: +converts the list of arguments to an array implicitly: .. code-block:: nimrod proc myWriteln(f: TFile, a: varargs[string]) = @@ -1016,7 +1016,7 @@ the ``of`` operator can be used to determine the object's type. Object fields that should be visible from outside the defining module, have to be marked by ``*``. In contrast to tuples, different object types are -never *equivalent*. Objects that have no ancestor are implicitely ``final`` +never *equivalent*. Objects that have no ancestor are implicitly ``final`` and thus have no hidden type field. One can use the ``inheritable`` pragma to introduce new object roots apart from ``system.TObject``. @@ -1253,7 +1253,7 @@ Nimrod supports these `calling conventions`:idx:\: any pragma annotations. It indicates that the procedure has a hidden implicit parameter (an *environment*). Proc vars that have the calling convention ``closure`` take up two machine words: One for the proc pointer - and another one for the pointer to implicitely passed environment. + and another one for the pointer to implicitly passed environment. `stdcall`:idx: This the stdcall convention as specified by Microsoft. The generated C @@ -1304,7 +1304,7 @@ The rules' purpose is to prevent the case that extending a non-``procvar`` procedure with default parameters breaks client code. The default calling convention is ``nimcall``, unless it is an inner proc ( -a proc inside of a proc). For an inner proc an analysis is performed wether it +a proc inside of a proc). For an inner proc an analysis is performed whether it accesses its environment. If it does so, it has the calling convention ``closure``, otherwise it has the calling convention ``nimcall``. @@ -1408,7 +1408,7 @@ currency. This can be solved with templates_. Void type ~~~~~~~~~ -The `void`:idx: type denotes the absense of any type. Parameters of +The `void`:idx: type denotes the absence of any type. Parameters of type ``void`` are treated as non-existent, ``void`` as a return type means that the procedure does not return a value: @@ -1693,7 +1693,7 @@ throws the expression's resulting value away. Ignoring the return value of a procedure without using a discard statement is a static error. -The return value can be ignored implicitely if the called proc/iterator has +The return value can be ignored implicitly if the called proc/iterator has been declared with the `discardable`:idx: pragma: .. code-block:: nimrod @@ -2375,6 +2375,72 @@ notation. (Thus an operator can have more than two parameters): assert `*+`(3, 4, 6) == `*`(a, `+`(b, c)) +Closures +~~~~~~~~ + +Procedures can appear at the top level in a module as well as inside other +scopes, in which case they are called nested procs. A nested proc can access +local variables from its enclosing scope and if it does so it becomes a +closure. Any captured variables are stored in a hidden additional argument +to the closure (its environment) and they are accessed by reference by both +the closure and its enclosing scope (i.e. any modifications made to them are +visible in both places). The closure environment may be allocated on the heap +or on the stack if the compiler determines that this would be safe. + +Anonymous Procs +~~~~~~~~~~~~~~~ + +Procs can also be treated as expressions, in which case it's allowed to omit +the proc's name. + +.. code-block:: nimrod + var cities = @["Frankfurt", "Tokyo", "New York"] + + cities.sort(proc (x,y: string): int = + cmp(x.len, y.len)) + + +Procs as expressions can appear both as nested procs and inside top level +executable code. + +Do notation +~~~~~~~~~~~ + +As a special more convenient notation, proc expressions involved in procedure +calls can use the ``do`` keyword: + +Syntax:: + primarySuffix ::= 'do' ['(' namedExprList ')'] ['->' typeDesc] ':' + +As a start, let's repeat the example from the previous section: + +.. code-block:: nimrod + cities.sort do (x,y: string) -> int: + cmp(x.len, y.len) + +``do`` is written after the parentheses enclosing the regular proc params. +The proc expression represented by the do block is appended to them. +Again, let's see the equivalent of the previous example: + +.. code-block:: nimrod + sort(cities) do (x,y: string) -> int: + cmp(x.len, y.len) + +Finally, more than one ``do`` blocks can appear in a single call: + +.. code-block:: nimrod + proc performWithUndo(task: proc(), undo: proc()) = ... + + performWithUndo do: + # multiple-line block of code + # to perform the task + do: + # code to undo it + +For compatibility with ``stmt`` templates and macros, the ``do`` keyword can be +omitted if the supplied proc doesn't have any parameters and return value. +The compatibility works in the other direction too as the ``do`` syntax can be +used with macros and templates expecting ``stmt`` blocks. Nonoverloadable builtins ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2549,7 +2615,7 @@ dispatching: Invocation of a multi-method cannot be ambiguous: collide 2 is preferred over collide 1 because the resolution works from left to right. -In the example ``TUnit, TThing`` is prefered over ``TThing, TUnit``. +In the example ``TUnit, TThing`` is preferred over ``TThing, TUnit``. **Performance note**: Nimrod does not produce a virtual method table, but generates dispatch trees. This avoids the expensive indirect branch for method @@ -2620,17 +2686,17 @@ as there are components in the tuple. The i'th iteration variable's type is the type of the i'th component. -Implict items/pairs invokations +Implict items/pairs invocations +++++++++++++++++++++++++++++++ If the for loop expression ``e`` does not denote an iterator and the for loop has exactly 1 variable, the for loop expression is rewritten to ``items(e)``; -ie. an ``items`` iterator is implicitely invoked: +ie. an ``items`` iterator is implicitly invoked: .. code-block:: nimrod for x in [1,2,3]: echo x -If the for loop has exactly 2 variables, a ``pairs`` iterator is implicitely +If the for loop has exactly 2 variables, a ``pairs`` iterator is implicitly invoked. Symbol lookup of the identifiers ``items``/``pairs`` is performed after @@ -2731,7 +2797,6 @@ Example: `type parameters`:idx:. Depending on context, the brackets are used either to introduce type parameters or to instantiate a generic proc, iterator or type. - Is operator ~~~~~~~~~~~ @@ -2770,21 +2835,12 @@ other interpretations: var y: type("a b c".split) -Type constraints -~~~~~~~~~~~~~~~~ - -`Type constraints`:idx: can be used to restrict the instantiation of a generic -type parameter. Only the specified types are valid for instantiation: +Type Classes +~~~~~~~~~~~~ -.. code-block:: nimrod - proc onlyIntOrString[T: int|string](x, y: T) = nil - - onlyIntOrString(450, 616) # valid - onlyIntOrString(5.0, 0.0) # type mismatch - onlyIntOrString("xy", 50) # invalid as 'T' cannot be both at the same time - -Apart from ordinary types, type constraints can also be of the -following *type classes*: +A `type class`:idx: is a special pseudo-type that can be used to match against +types in the context of overload resolution or the ``is`` operator. +Nimrod supports the following built-in type classes: ================== =================================================== type class matches @@ -2801,25 +2857,95 @@ type class matches ``array`` any array type ``set`` any set type ``seq`` any seq type +``auto`` any type ================== =================================================== -The following example is taken directly from the system module: +Furthermore, every generic type automatically creates a type class of the same +name that will match any instantiation of the generic type. + +Type classes can be combined using the standard boolean operators to form +more complex type classes: + +.. code-block:: nimrod + # create a type class that will match all tuple and object types + type TRecordType = tuple or object + + proc printFields(rec: TRecordType) = + for key, value in fieldPairs(rec): + echo key, " = ", value + +Procedures utilizing type classes in such manner are considered to be +`implicitly generic`:idx:. They will be instantiated once for each unique +combination of param types used within the program. + +Nimrod also allows for type classes and regular types to be specified +as `type constraints`:idx: of the generic type parameter: .. code-block:: nimrod - proc `==`*[T: tuple](x, y: T): bool = + proc onlyIntOrString[T: int|string](x, y: T) = nil + + onlyIntOrString(450, 616) # valid + onlyIntOrString(5.0, 0.0) # type mismatch + onlyIntOrString("xy", 50) # invalid as 'T' cannot be both at the same time + +By default, during overload resolution each named type class will bind to +exactly one concrete type. Here is an example taken directly from the system +module to illustrate this: + +.. code-block:: nimrod + proc `==`*(x, y: tuple): bool = + ## requires `x` and `y` to be of the same tuple type ## generic ``==`` operator for tuples that is lifted from the components ## of `x` and `y`. for a, b in fields(x, y): if a != b: return false return true +Alternatively, the ``distinct`` type modifier can be applied to the type class +to allow each param matching the type class to bind to a different type. + +If a proc param doesn't have a type specified, Nimrod will use the +``distinct auto`` type class (also known as ``any``): + +.. code-block:: nimrod + # allow any combination of param types + proc concat(a, b): string = $a & $b + +Procs written with the implicitly generic style will often need to refer to the +type parameters of the matched generic type. They can be easily accessed using +the dot syntax: + +.. code-block:: nimrod + type TMatrix[T, Rows, Columns] = object + ... + + proc `[]`(m: TMatrix, row, col: int): TMatrix.T = + m.data[col * high(TMatrix.Columns) + row] + +If anonymous type classes are used, the ``type`` operator can be used to +discover the instantiated type of each param. + +User defined type classes +~~~~~~~~~~~~~~~~~~~~~~~~~ + +To be written. + +Return Type Inference +~~~~~~~~~~~~~~~~~~~~~ + +If a type class is used as the return type of a proc and it won't be bound to +a concrete type by some of the proc params, Nimrod will infer the return type +from the proc body. This is usually used with the ``auto`` type class: + +.. code-block:: nimrod + proc makePair(a, b): auto = (first: a, second: b) Symbol lookup in generics ~~~~~~~~~~~~~~~~~~~~~~~~~ Symbols in generics are looked up in two different contexts: Both the context at definition and the context at instantiation are considered for any symbol -occuring in a generic: +occurring in a generic: .. code-block:: nimrod type @@ -2886,7 +3012,7 @@ So ordinary templates cannot receive undeclared identifiers: declareInt(x) # error: unknown identifier: 'x' An ``immediate`` template does not participate in overload resolution and so -its arguments are not checked for semantics before invokation. So they can +its arguments are not checked for semantics before invocation. So they can receive undeclared identifiers: .. code-block:: nimrod @@ -2948,7 +3074,7 @@ parameter. **Note:** The symbol binding rules for templates might change! -Symbol binding within templates happens after template instantation: +Symbol binding within templates happens after template instantiation: .. code-block:: nimrod # Module A @@ -3089,7 +3215,7 @@ template parameter, it is an inject'ed symbol: .. code-block:: nimrod template withFile(f, fn, mode: expr, actions: stmt): stmt {.immediate.} = block: - var f: TFile # since 'f' is a template param, it's injected implicitely + var f: TFile # since 'f' is a template param, it's injected implicitly ... withFile(txt, "ttempl3.txt", fmWrite): @@ -3230,7 +3356,7 @@ The macro call expands to: However, the symbols ``write``, ``writeln`` and ``stdout`` are already bound and are not looked up again. As the example shows, ``bindSym`` does work with -overloaded symbols implicitely. +overloaded symbols implicitly. Statement Macros @@ -3297,6 +3423,78 @@ This is a simple syntactic transformation into: proc p() = nil +Special Types +------------- + +typedesc +~~~~~~~~ + +`typedesc` is a special type allowing you to treat types as compile-time values +(i.e. if types are compile-time values and all values have a type, then + typedesc must be their type). + +When used as a regular proc param, typedesc acts as a type class. The proc +will be instantiated for each unique type parameter and you can refer to the +instantiation type using the param name: + +.. code-block:: nimrod + + proc new(T: typedesc): ref T = + echo "allocating ", T.name + new(result) + + var n = TNode.new + var tree = new(TBinaryTree[int]) + +When used with macros and .compileTime. procs on the other hand, the compiler +don't need to instantiate the code multiple times, because types then can be +manipulated using the unified internal symbol representation. In such context +typedesc acts as any other type. You can create variables, store typedesc +values inside containers and so on. For example, here is how we can create +a type-safe wrapper for the unsafe `printf` function form C: + +.. code-block:: nimrod + macro safePrintF(formatString: string{lit}, args: vararg[expr]): expr = + var i = 0 + for c in formatChars(formatString): + const FormatChars = { + 'c': char, + 'd', 'i', 'x', 'X': int, + 'f', 'e', 'E', 'g', 'G': float, + 's': string, + 'p': pointer, + } + + var expectedType = find(FormatChars, c, EOutOfRange) + var actualType = args[i].getType + inc i + + if expectedType == EOutOfRange: + error c & " is not a valid format character" + elif expectedType != actualType: + error "type mismatch for argument ", i, ". expected type: ", + expectedType.name, ", actual type: ", actualType.name + + # keep the original callsite, but use cprintf instead + result = callsite() + result[0] = newIdentNode(!"cprintf") + + +Overload resolution can be further influenced by constraining the set of +types that will match the typedesc param: + +.. code-block:: nimrod + + template maxval(T: typedesc[int]): int = high(int) + template maxval(T: typedesc[float]): float = Inf + + var i = int.maxval + var f = float.maxval + var s = string.maxval # error, maxval is not implemented for string + +The constraint can be a concrete type or a type class. + + Modules ------- Nimrod supports splitting a program into pieces by a `module`:idx: concept. @@ -3442,6 +3640,18 @@ proc with no side effects: func `+` (x, y: int): int +destructor pragma +----------------- +`RAII`:idx: +`automatic variables`:idx: +`destructors`:idx: +The `destructor` pragma is used to mark a proc to act as a type destructor. +The proc must have a single parameter, having a concrete type. +Destructors will be automatically invoked when a local stack variable goes +out of scope. If a record type features a field with destructable type and +the user have not provided explicit implementation, Nimrod will automatically +generate a destructor for the record type. + procvar pragma -------------- The `procvar`:idx: pragma is used to mark a proc that it can be passed to a @@ -3586,7 +3796,7 @@ If the ``line`` pragma is used with a parameter, the parameter needs be a linearScanEnd pragma -------------------- The `linearScanEnd`:idx: pragma can be used to tell the compiler how to -compile a Nimrod `case`:idx: statement. Syntactially it has to be used as a +compile a Nimrod `case`:idx: statement. Syntactically it has to be used as a statement: .. code-block:: nimrod @@ -3722,7 +3932,7 @@ DeadCodeElim pragma ------------------- The `deadCodeElim`:idx: pragma only applies to whole modules: It tells the compiler to activate (or deactivate) dead code elimination for the module the -pragma appers in. +pragma appears in. The ``--deadCodeElim:on`` command line switch has the same effect as marking every module with ``{.deadCodeElim:on}``. However, for some modules such as |