diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/docgen.txt | 2 | ||||
-rw-r--r-- | doc/grammar.txt | 34 | ||||
-rw-r--r-- | doc/keywords.txt | 2 | ||||
-rw-r--r-- | doc/manual/generics.txt | 97 | ||||
-rw-r--r-- | doc/manual/pragmas.txt | 62 | ||||
-rw-r--r-- | doc/manual/procs.txt | 43 | ||||
-rw-r--r-- | doc/manual/threads.txt | 42 | ||||
-rw-r--r-- | doc/manual/type_bound_ops.txt | 58 | ||||
-rw-r--r-- | doc/manual/type_rel.txt | 169 | ||||
-rw-r--r-- | doc/manual/typedesc.txt | 31 | ||||
-rw-r--r-- | doc/manual/types.txt | 26 | ||||
-rw-r--r-- | doc/nimc.txt | 16 | ||||
-rw-r--r-- | doc/tut2.txt | 25 |
13 files changed, 385 insertions, 222 deletions
diff --git a/doc/docgen.txt b/doc/docgen.txt index f4e28a49f..40c464ebd 100644 --- a/doc/docgen.txt +++ b/doc/docgen.txt @@ -195,7 +195,7 @@ In the case of Nim's own documentation, the ``txt`` value is just a commit hash to append to a formatted URL to https://github.com/Araq/Nim. The ``tools/nimweb.nim`` helper queries the current git commit hash during doc generation, but since you might be working on an unpublished repository, it -also allows specifying a ``githash`` value in ``web/nim.ini`` to force a +also allows specifying a ``githash`` value in ``web/website.ini`` to force a specific commit in the output. diff --git a/doc/grammar.txt b/doc/grammar.txt index 2b04e6ca8..b53515495 100644 --- a/doc/grammar.txt +++ b/doc/grammar.txt @@ -3,17 +3,13 @@ comma = ',' COMMENT? semicolon = ';' COMMENT? colon = ':' COMMENT? colcom = ':' COMMENT? - -operator = OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9 | OP10 +operator = OP0 | OP1 | OP2 | OP3 | OP4 | OP5 | OP6 | OP7 | OP8 | OP9 | 'or' | 'xor' | 'and' | 'is' | 'isnot' | 'in' | 'notin' | 'of' - | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'addr' | 'static' | '..' - + | 'div' | 'mod' | 'shl' | 'shr' | 'not' | 'static' | '..' prefixOperator = operator - optInd = COMMENT? optPar = (IND{>} | IND{=})? - simpleExpr = arrowExpr (OP0 optInd arrowExpr)* arrowExpr = assignExpr (OP1 optInd assignExpr)* assignExpr = orExpr (OP2 optInd orExpr)* @@ -26,20 +22,20 @@ plusExpr = mulExpr (OP8 optInd mulExpr)* mulExpr = dollarExpr (OP9 optInd dollarExpr)* dollarExpr = primary (OP10 optInd primary)* symbol = '`' (KEYW|IDENT|literal|(operator|'('|')'|'['|']'|'{'|'}'|'=')+)+ '`' - | IDENT + | IDENT | 'addr' | 'type' indexExpr = expr indexExprList = indexExpr ^+ comma exprColonEqExpr = expr (':'|'=' expr)? exprList = expr ^+ comma -dotExpr = expr '.' optInd ('type' | 'addr' | symbol) -qualifiedIdent = symbol ('.' optInd ('type' | 'addr' | symbol))? +dotExpr = expr '.' optInd symbol +qualifiedIdent = symbol ('.' optInd symbol)? exprColonEqExprList = exprColonEqExpr (comma exprColonEqExpr)* (comma)? setOrTableConstr = '{' ((exprColonEqExpr comma)* | ':' ) '}' castExpr = 'cast' '[' optInd typeDesc optPar ']' '(' optInd expr optPar ')' parKeyw = 'discard' | 'include' | 'if' | 'while' | 'case' | 'try' | 'finally' | 'except' | 'for' | 'block' | 'const' | 'let' | 'when' | 'var' | 'mixin' -par = '(' optInd (&parKeyw complexOrSimpleStmt ^+ ';' +par = '(' optInd (&parKeyw complexOrSimpleStmt ^+ ';' | simpleExpr ('=' expr (';' complexOrSimpleStmt ^+ ';' )? )? | (':' expr)? (',' (exprColonEqExpr comma?)*)? )? optPar ')' @@ -56,11 +52,11 @@ identOrLiteral = generalizedLit | symbol | literal tupleConstr = '(' optInd (exprColonEqExpr comma?)* optPar ')' arrayConstr = '[' optInd (exprColonEqExpr comma?)* optPar ']' primarySuffix = '(' (exprColonEqExpr comma?)* ')' doBlocks? - | doBlocks - | '.' optInd ('type' | 'addr' | symbol) generalizedLit? - | '[' optInd indexExprList optPar ']' - | '{' optInd indexExprList optPar '}' - | &( '`'|IDENT|literal|'cast') expr # command syntax + | doBlocks + | '.' optInd symbol generalizedLit? + | '[' optInd indexExprList optPar ']' + | '{' optInd indexExprList optPar '}' + | &( '`'|IDENT|literal|'cast'|'addr'|'type') expr # command syntax condExpr = expr colcom expr optInd ('elif' expr colcom expr optInd)* 'else' colcom expr @@ -77,6 +73,7 @@ inlTupleDecl = 'tuple' [' optInd (identColonEquals (comma/semicolon)?)* optPar ']' extTupleDecl = 'tuple' COMMENT? (IND{>} identColonEquals (IND{=} identColonEquals)*)? +tupleClass = 'tuple' paramList = '(' declColonEquals ^* (comma/semicolon) ')' paramListArrow = paramList? ('->' optInd typeDesc)? paramListColon = paramList? (':' optInd typeDesc)? @@ -89,17 +86,16 @@ expr = (ifExpr | caseExpr | tryExpr) / simpleExpr -typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'type' | 'tuple' +typeKeyw = 'var' | 'ref' | 'ptr' | 'shared' | 'tuple' | 'proc' | 'iterator' | 'distinct' | 'object' | 'enum' primary = typeKeyw typeDescK / prefixOperator* identOrLiteral primarySuffix* - / 'addr' primary / 'static' primary / 'bind' primary typeDesc = simpleExpr typeDefAux = simpleExpr - | 'generic' typeClass -macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt + | 'concept' typeClass +macroColon = ':' stmt? ( IND{=} 'of' exprList ':' stmt | IND{=} 'elif' expr ':' stmt | IND{=} 'except' exprList ':' stmt | IND{=} 'else' ':' stmt )* diff --git a/doc/keywords.txt b/doc/keywords.txt index 7a4f8c696..405bf1981 100644 --- a/doc/keywords.txt +++ b/doc/keywords.txt @@ -1,6 +1,6 @@ addr and as asm atomic bind block break -case cast const continue converter +case cast concept const continue converter defer discard distinct div do elif else end enum except export finally for from func diff --git a/doc/manual/generics.txt b/doc/manual/generics.txt index f3e7b7b4c..2736f88fb 100644 --- a/doc/manual/generics.txt +++ b/doc/manual/generics.txt @@ -60,7 +60,7 @@ Is operator ----------- The ``is`` operator checks for type equivalence at compile time. It is -therefore very useful for type specialization within generic code: +therefore very useful for type specialization within generic code: .. code-block:: nim type @@ -75,7 +75,7 @@ Type operator ------------- The ``type`` (in many other languages called `typeof`:idx:) operator can -be used to get the type of an expression: +be used to get the type of an expression: .. code-block:: nim var x = 0 @@ -88,7 +88,7 @@ other interpretations: .. code-block:: nim import strutils - + # strutils contains both a ``split`` proc and iterator, but since an # an iterator is the preferred interpretation, `y` has the type ``string``: var y: type("a b c".split) @@ -98,7 +98,7 @@ Type Classes ------------ A type class is a special pseudo-type that can be used to match against -types in the context of overload resolution or the ``is`` operator. +types in the context of overload resolution or the ``is`` operator. Nim supports the following built-in type classes: ================== =================================================== @@ -116,7 +116,7 @@ type class matches ``array`` any array type ``set`` any set type ``seq`` any seq type -``auto`` any type +``auto`` any type ================== =================================================== Furthermore, every generic type automatically creates a type class of the same @@ -134,7 +134,7 @@ more complex type classes: 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 +`implicitly generic`:idx:. They will be instantiated once for each unique combination of param types used within the program. Nim also allows for type classes and regular types to be specified @@ -142,7 +142,7 @@ as `type constraints`:idx: of the generic type parameter: .. code-block:: nim proc onlyIntOrString[T: int|string](x, y: T) = discard - + onlyIntOrString(450, 616) # valid onlyIntOrString(5.0, 0.0) # type mismatch onlyIntOrString("xy", 50) # invalid as 'T' cannot be both at the same time @@ -152,7 +152,7 @@ exactly one concrete type. Here is an example taken directly from the system module to illustrate this: .. code-block:: nim - proc `==`*(x, y: tuple): bool = + 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`. @@ -160,8 +160,8 @@ module to illustrate this: for a, b in fields(x, y): if a != b: result = false -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. +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, Nim will use the ``distinct auto`` type class (also known as ``any``): @@ -178,7 +178,7 @@ the dot syntax: type Matrix[T, Rows, Columns] = object ... - proc `[]`(m: Matrix, row, col: int): Matrix.T = + proc `[]`(m: Matrix, row, col: int): Matrix.T = m.data[col * high(Matrix.Columns) + row] Alternatively, the `type` operator can be used over the proc params for similar @@ -189,7 +189,7 @@ type, this results in another more specific type class: .. code-block:: nim seq[ref object] # Any sequence storing references to any object type - + type T1 = auto proc foo(s: seq[T1], e: T1) # seq[T1] is the same as just `seq`, but T1 will be allowed to bind @@ -203,34 +203,33 @@ be inferred to have the equivalent of the `any` type class and thus they will match anything without discrimination. -User defined type classes -------------------------- +Concepts +-------- -**Note**: User defined type classes are still in development. +**Note**: Concepts are still in development. -The user-defined type classes are available in two flavours - declarative and -imperative. Both are used to specify an arbitrary set of requirements that the -matched type must satisfy. +Concepts, also known as "user-defined type classes", are used to specify an +arbitrary set of requirements that the matched type must satisfy. -Declarative type classes are written in the following form: +Concepts are written in the following form: .. code-block:: nim type - Comparable = generic x, y + Comparable = concept x, y (x < y) is bool - Container[T] = generic c - c.len is ordinal + Container[T] = concept c + c.len is Ordinal items(c) is iterator for value in c: type(value) is T -The type class will be matched if: +The concept is a match if: a) all of the expressions within the body can be compiled for the tested type b) all statically evaluatable boolean expressions in the body must be true -The identifiers following the `generic` keyword represent instances of the +The identifiers following the ``concept`` keyword represent instances of the currently matched type. These instances can act both as variables of the type, when used in contexts where a value is expected, and as the type itself when used in contexts where a type is expected. @@ -240,45 +239,21 @@ type signatures of the required operations, but since type inference and default parameters are still applied in the provided block, it's also possible to encode usage protocols that do not reveal implementation details. -As a special rule providing further convenience when writing type classes, any +As a special rule providing further convenience when writing concepts, any type value appearing in a callable expression will be treated as a variable of the designated type for overload resolution purposes, unless the type value was passed in its explicit ``typedesc[T]`` form: .. code-block:: nim type - OutputStream = generic S - write(var S, string) + OutputStream = concept s + write(var s, string) -Much like generics, the user defined type classes will be instantiated exactly -once for each tested type and any static code included within them will also be +Much like generics, concepts are instantiated exactly +once for each tested type and any static code included within them is also executed once. -Type inference with type classes --------------------------------- - -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, Nim will infer the return type -from the proc body. This is usually used with the ``auto`` type class: - -.. code-block:: nim - proc makePair(a, b): auto = (first: a, second: b) - -The return type will be treated as an additional generic param and can be -explicitly specified at call sites as any other generic param. - -Future versions of Nim may also support overloading based on the return type -of the overloads. In such settings, the expected result type at call sites may -also influence the inferred return type. - -.. - Likewise, if a type class is used in another position where Nim expects a - concrete type (e.g. a variable declaration or a type coercion), Nim will try - to infer the concrete type by applying the matching algorithm that also used - in overload resolution. - - Symbol lookup in generics ------------------------- @@ -293,12 +268,12 @@ at definition and the context at instantiation are considered: .. code-block:: nim type Index = distinct int - + proc `==` (a, b: Index): bool {.borrow.} - + var a = (0, 0.Index) var b = (0, 0.Index) - + echo a == b # works! In the example the generic ``==`` for tuples (as defined in the system module) @@ -307,7 +282,7 @@ the ``Index`` type is defined *after* the ``==`` for tuples; yet the example compiles as the instantiation takes the currently defined symbols into account too. -A symbol can be forced to be open by a `mixin`:idx: declaration: +A symbol can be forced to be open by a `mixin`:idx: declaration: .. code-block:: nim proc create*[T](): ref T = @@ -321,16 +296,16 @@ A symbol can be forced to be open by a `mixin`:idx: declaration: Bind statement -------------- -The ``bind`` statement is the counterpart to the ``mixin`` statement. It +The ``bind`` statement is the counterpart to the ``mixin`` statement. It can be used to explicitly declare identifiers that should be bound early (i.e. the identifiers should be looked up in the scope of the template/generic definition): .. code-block:: nim # Module A - var + var lastId = 0 - + template genId*: expr = bind lastId inc(lastId) @@ -339,7 +314,7 @@ definition): .. code-block:: nim # Module B import A - + echo genId() But a ``bind`` is rarely useful because symbol binding from the definition diff --git a/doc/manual/pragmas.txt b/doc/manual/pragmas.txt index 34428233f..46fd89b13 100644 --- a/doc/manual/pragmas.txt +++ b/doc/manual/pragmas.txt @@ -14,7 +14,7 @@ deprecated pragma The deprecated pragma is used to mark a symbol as deprecated: -.. code-block:: nimrod +.. code-block:: nim proc p() {.deprecated.} var x {.deprecated.}: char @@ -22,7 +22,7 @@ It can also be used as a statement. Then it takes a list of *renamings*. The upcoming ``nimfix`` tool can automatically update the code and perform these renamings: -.. code-block:: nimrod +.. code-block:: nim type File = object Stream = ref object @@ -78,7 +78,7 @@ as helpers for macros. noReturn pragma --------------- -The ``noreturn`` pragma is used to mark a proc that never returns. +The ``noreturn`` pragma is used to mark a proc that never returns. acyclic pragma @@ -122,25 +122,25 @@ shallow pragma -------------- The ``shallow`` pragma affects the semantics of a type: The compiler is allowed to make a shallow copy. This can cause serious semantic issues and -break memory safety! However, it can speed up assignments considerably, -because the semantics of Nim require deep copying of sequences and strings. +break memory safety! However, it can speed up assignments considerably, +because the semantics of Nim require deep copying of sequences and strings. This can be expensive, especially if sequences are used to build a tree -structure: +structure: .. code-block:: nim type NodeKind = enum nkLeaf, nkInner Node {.final, shallow.} = object case kind: NodeKind - of nkLeaf: + of nkLeaf: strVal: string - of nkInner: + of nkInner: children: seq[Node] pure pragma ----------- -An object type can be marked with the ``pure`` pragma so that its type +An object type can be marked with the ``pure`` pragma so that its type field which is used for runtime type identification is omitted. This used to be necessary for binary compatibility with other compiled languages. @@ -163,12 +163,12 @@ error pragma ------------ The ``error`` pragma is used to make the compiler output an error message with the given content. Compilation does not necessarily abort after an error -though. +though. The ``error`` pragma can also be used to annotate a symbol (like an iterator or proc). The *usage* of the symbol then triggers a compile-time error. This is especially useful to rule out that some -operation is valid due to overloading and type conversions: +operation is valid due to overloading and type conversions: .. code-block:: nim ## check that underlying int values are compared and not the pointers: @@ -201,7 +201,7 @@ The ``line`` pragma can be used to affect line information of the annotated statement as seen in stack backtraces: .. code-block:: nim - + template myassert*(cond: expr, msg = "") = if not cond: # change run-time line information of the 'raise' statement: @@ -215,26 +215,26 @@ If the ``line`` pragma is used with a parameter, the parameter needs be a linearScanEnd pragma -------------------- -The ``linearScanEnd`` pragma can be used to tell the compiler how to +The ``linearScanEnd`` pragma can be used to tell the compiler how to compile a Nim `case`:idx: statement. Syntactically it has to be used as a statement: .. code-block:: nim case myInt - of 0: + of 0: echo "most common case" - of 1: + of 1: {.linearScanEnd.} echo "second most common case" of 2: echo "unlikely: use branch table" else: echo "unlikely too: use branch table for ", myInt -In the example, the case branches ``0`` and ``1`` are much more common than -the other cases. Therefore the generated assembler code should test for these -values first, so that the CPU's branch predictor has a good chance to succeed +In the example, the case branches ``0`` and ``1`` are much more common than +the other cases. Therefore the generated assembler code should test for these +values first, so that the CPU's branch predictor has a good chance to succeed (avoiding an expensive CPU pipeline stall). The other cases might be put into a jump table for O(1) overhead, but at the cost of a (very likely) pipeline -stall. +stall. The ``linearScanEnd`` pragma should be put into the last branch that should be tested against via linear scanning. If put into the last branch of the @@ -243,8 +243,8 @@ whole ``case`` statement, the whole ``case`` statement uses linear scanning. computedGoto pragma ------------------- -The ``computedGoto`` pragma can be used to tell the compiler how to -compile a Nim `case`:idx: in a ``while true`` statement. +The ``computedGoto`` pragma can be used to tell the compiler how to +compile a Nim `case`:idx: in a ``while true`` statement. Syntactically it has to be used as a statement inside the loop: .. code-block:: nim @@ -278,21 +278,21 @@ Syntactically it has to be used as a statement inside the loop: of enumE: break inc(pc) - + vm() As the example shows ``computedGoto`` is mostly useful for interpreters. If -the underlying backend (C compiler) does not support the computed goto +the underlying backend (C compiler) does not support the computed goto extension the pragma is simply ignored. unroll pragma ------------- The ``unroll`` pragma can be used to tell the compiler that it should unroll -a `for`:idx: or `while`:idx: loop for runtime efficiency: +a `for`:idx: or `while`:idx: loop for runtime efficiency: .. code-block:: nim - proc searchChar(s: string, c: char): int = + proc searchChar(s: string, c: char): int = for i in 0 .. s.high: {.unroll: 4.} if s[i] == c: return i @@ -440,7 +440,7 @@ Example: Please note that if a callable symbol is never used in this scenario, its body will never be compiled. This is the default behavior leading to best compilation - times, but if exhaustive compilation of all definitions is required, using + times, but if exhaustive compilation of all definitions is required, using ``nim check`` provides this option as well. Example: @@ -461,9 +461,9 @@ Example: pragma pragma ------------- -The ``pragma`` pragma can be used to declare user defined pragmas. This is -useful because Nim's templates and macros do not affect pragmas. User -defined pragmas are in a different module-wide scope than all other symbols. +The ``pragma`` pragma can be used to declare user defined pragmas. This is +useful because Nim's templates and macros do not affect pragmas. User +defined pragmas are in a different module-wide scope than all other symbols. They cannot be imported from a module. Example: @@ -473,8 +473,8 @@ Example: {.pragma: rtl, exportc, dynlib, cdecl.} else: {.pragma: rtl, importc, dynlib: "client.dll", cdecl.} - - proc p*(a, b: int): int {.rtl.} = + + proc p*(a, b: int): int {.rtl.} = result = a+b In the example a new pragma named ``rtl`` is introduced that either imports diff --git a/doc/manual/procs.txt b/doc/manual/procs.txt index 9b04bf518..9de984ecf 100644 --- a/doc/manual/procs.txt +++ b/doc/manual/procs.txt @@ -121,7 +121,7 @@ different; for this a special setter syntax is needed: .. code-block:: nim type - Socket* = object of RootObj + Socket* = ref object of RootObj FHost: int # cannot be accessed from the outside of the module # the `F` prefix is a convention to avoid clashes since # the accessors are named `host` @@ -134,8 +134,8 @@ different; for this a special setter syntax is needed: ## getter of hostAddr s.FHost - var - s: Socket + var s: Socket + new s s.host = 34 # same as `host=`(s, 34) @@ -351,32 +351,32 @@ dispatch. .. code-block:: nim type - Expression = object of RootObj ## abstract base class for an expression - Literal = object of Expression + Expression = ref object of RootObj ## abstract base class for an expression + Literal = ref object of Expression x: int - PlusExpr = object of Expression - a, b: ref Expression - - method eval(e: ref Expression): int = + PlusExpr = ref object of Expression + a, b: Expression + + method eval(e: Expression): int = # override this base method quit "to override!" - method eval(e: ref Literal): int = return e.x - - method eval(e: ref PlusExpr): int = + method eval(e: Literal): int = return e.x + + method eval(e: PlusExpr): int = # watch out: relies on dynamic binding result = eval(e.a) + eval(e.b) - proc newLit(x: int): ref Literal = + proc newLit(x: int): Literal = new(result) result.x = x - - proc newPlus(a, b: ref Expression): ref PlusExpr = + + proc newPlus(a, b: Expression): PlusExpr = new(result) result.a = a result.b = b - - echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4))) + +echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4))) In the example the constructors ``newLit`` and ``newPlus`` are procs because they should use static binding, but ``eval`` is a method because it @@ -387,8 +387,8 @@ dispatching: .. code-block:: nim type - Thing = object of RootObj - Unit = object of Thing + Thing = ref object of RootObj + Unit = ref object of Thing x: int method collide(a, b: Thing) {.inline.} = @@ -400,8 +400,9 @@ dispatching: method collide(a: Unit, b: Thing) {.inline.} = echo "2" - var - a, b: Unit + var a, b: Unit + new a + new b collide(a, b) # output: 2 diff --git a/doc/manual/threads.txt b/doc/manual/threads.txt index 245545f6f..fc3040c87 100644 --- a/doc/manual/threads.txt +++ b/doc/manual/threads.txt @@ -1,16 +1,16 @@ Threads ======= -To enable thread support the ``--threads:on`` command line switch needs to -be used. The ``system`` module then contains several threading primitives. -See the `threads <threads.html>`_ and `channels <channels.html>`_ modules +To enable thread support the ``--threads:on`` command line switch needs to +be used. The ``system`` module then contains several threading primitives. +See the `threads <threads.html>`_ and `channels <channels.html>`_ modules for the low level thread API. There are also high level parallelism constructs available. See `spawn`_ for further details. Nim's memory model for threads is quite different than that of other common -programming languages (C, Pascal, Java): Each thread has its own (garbage -collected) heap and sharing of memory is restricted to global variables. This -helps to prevent race conditions. GC efficiency is improved quite a lot, +programming languages (C, Pascal, Java): Each thread has its own (garbage +collected) heap and sharing of memory is restricted to global variables. This +helps to prevent race conditions. GC efficiency is improved quite a lot, because the GC never has to stop other threads and see what they reference. Memory allocation requires no lock at all! This design easily scales to massive multicore processors that are becoming the norm. @@ -22,10 +22,10 @@ Thread pragma A proc that is executed as a new thread of execution should be marked by the ``thread`` pragma for reasons of readability. The compiler checks for violations of the `no heap sharing restriction`:idx:\: This restriction implies -that it is invalid to construct a data structure that consists of memory +that it is invalid to construct a data structure that consists of memory allocated from different (thread local) heaps. -A thread proc is passed to ``createThread`` or ``spawn`` and invoked +A thread proc is passed to ``createThread`` or ``spawn`` and invoked indirectly; so the ``thread`` pragma implies ``procvar``. @@ -34,7 +34,7 @@ GC safety We call a proc ``p`` `GC safe`:idx: when it doesn't access any global variable that contains GC'ed memory (``string``, ``seq``, ``ref`` or a closure) either -directly or indirectly through a call to a GC unsafe proc. +directly or indirectly through a call to a GC unsafe proc. The `gcsafe`:idx: annotation can be used to mark a proc to be gcsafe, otherwise this property is inferred by the compiler. Note that ``noSideEfect`` @@ -45,10 +45,9 @@ contain a ``ref`` or ``closure`` type. This enforces the *no heap sharing restriction*. Routines that are imported from C are always assumed to be ``gcsafe``. -To enable the GC-safety checking the ``--threadAnalysis:on`` command line -switch must be used. This is a temporary workaround to ease the porting effort -from old code to the new threading model. In the future the thread analysis -will always be performed. +To disable the GC-safety checking the ``--threadAnalysis:off`` command line +switch can be used. This is a temporary workaround to ease the porting effort +from old code to the new threading model. Future directions: @@ -59,13 +58,13 @@ Future directions: Threadvar pragma ---------------- -A global variable can be marked with the ``threadvar`` pragma; it is +A global variable can be marked with the ``threadvar`` pragma; it is a `thread-local`:idx: variable then: .. code-block:: nim var checkpoints* {.threadvar.}: seq[string] -Due to implementation restrictions thread local variables cannot be +Due to implementation restrictions thread local variables cannot be initialized within the ``var`` section. (Every thread local variable needs to be replicated at thread creation.) @@ -73,7 +72,7 @@ be replicated at thread creation.) Threads and exceptions ---------------------- -The interaction between threads and exceptions is simple: A *handled* exception +The interaction between threads and exceptions is simple: A *handled* exception in one thread cannot affect any other thread. However, an *unhandled* exception in one thread terminates the whole *process*! @@ -82,7 +81,7 @@ in one thread terminates the whole *process*! Parallel & Spawn ================ -Nim has two flavors of parallelism: +Nim has two flavors of parallelism: 1) `Structured`:idx: parallelism via the ``parallel`` statement. 2) `Unstructured`:idx: parallelism via the standalone ``spawn`` statement. @@ -115,7 +114,7 @@ Spawn statement proc processLine(line: string) = discard "do some heavy lifting here" - + for x in lines("myinput.txt"): spawn processLine(x) sync() @@ -144,7 +143,7 @@ wait on multiple flow variables at the same time: .. code-block:: nim import threadpool, ... - + # wait until 2 out of 3 servers received the update: proc main = var responses = newSeq[RawFlowVar](3) @@ -203,8 +202,7 @@ restrictions / changes: the ``parallel`` section. This is called the *immutability check*. Currently it is not specified what exactly "complex location" means. We need to make this an optimization! -* Every array access has to be provably within bounds. This is called +* Every array access has to be provably within bounds. This is called the *bounds check*. * Slices are optimized so that no copy is performed. This optimization is not - yet performed for ordinary slices outside of a ``parallel`` section. Slices - are also special in that they currently do not support negative indexes! + yet performed for ordinary slices outside of a ``parallel`` section. diff --git a/doc/manual/type_bound_ops.txt b/doc/manual/type_bound_ops.txt index 59d55a6cd..efa5578d4 100644 --- a/doc/manual/type_bound_ops.txt +++ b/doc/manual/type_bound_ops.txt @@ -21,27 +21,49 @@ helper distinct or object type has to be used for one pointer type. operator `=` ------------ -This operator is the assignment operator. Note that in the contexts -like ``let v = expr``, ``var v = expr``, ``parameter = defaultValue`` or for -parameter passing no assignment is performed. The ``override`` pragma is -optional for overriding ``=``. +This operator is the assignment operator. Note that in the contexts +``result = expr``, ``parameter = defaultValue`` or for +parameter passing no assignment is performed. For a type ``T`` that has an +overloaded assignment operator ``var v = T()`` is rewritten +to ``var v: T; v = T()``; in other words ``var`` and ``let`` contexts do count +as assignments. + +The assignment operator needs to be attached to an object or distinct +type ``T``. Its signature has to be ``(var T, T)``. Example: + +.. code-block:: nim + type + Concrete = object + a, b: string + + proc `=`(d: var Concrete; src: Concrete) = + shallowCopy(d.a, src.a) + shallowCopy(d.b, src.b) + echo "Concrete '=' called" + + var x, y: array[0..2, Concrete] + var cA, cB: Concrete + + var cATup, cBTup: tuple[x: int, ha: Concrete] + + x = y + cA = cB + cATup = cBTup -**Note**: Overriding of operator ``=`` is not yet implemented. destructors ----------- A destructor must have a single parameter with a concrete type (the name of a -generic type is allowed too). The name of the destructor has to be ``destroy`` -and it need to be annotated with the ``override`` pragma. +generic type is allowed too). The name of the destructor has to be ``=destroy``. -``destroy(v)`` will be automatically invoked for every local stack +``=destroy(v)`` will be automatically invoked for every local stack variable ``v`` that goes out of scope. -If a structured type features a field with destructable type and +If a structured type features a field with destructable type and the user has not provided an explicit implementation, a destructor for the -structured type will be automatically generated. Calls to any base class +structured type will be automatically generated. Calls to any base class destructors in both user-defined and generated destructors will be inserted. A destructor is attached to the type it destructs; expressions of this type @@ -52,13 +74,13 @@ can then only be used in *destructible contexts* and as parameters: MyObj = object x, y: int p: pointer - - proc destroy(o: var MyObj) {.override.} = + + proc `=destroy`(o: var MyObj) = if o.p != nil: dealloc o.p - + proc open: MyObj = result = MyObj(x: 1, y: 2, p: alloc(3)) - + proc work(o: MyObj) = echo o.x # No destructor invoked here for 'o' as 'o' is a parameter. @@ -68,7 +90,7 @@ can then only be used in *destructible contexts* and as parameters: var x = open() # valid: pass 'x' to some other proc: work(x) - + # Error: usage of a type with a destructor in a non destructible context echo open() @@ -85,7 +107,7 @@ be destructed at its scope exit. Later versions of the language will improve the support of destructors. Be aware that destructors are not called for objects allocated with ``new``. -This may change in future versions of language, but for now the ``finalizer`` +This may change in future versions of language, but for now the `finalizer`:idx: parameter to ``new`` has to be used. **Note**: Destructors are still experimental and the spec might change @@ -95,7 +117,7 @@ significantly in order to incorporate an escape analysis. deepCopy -------- -``deepCopy`` is a builtin that is invoked whenever data is passed to +``=deepCopy`` is a builtin that is invoked whenever data is passed to a ``spawn``'ed proc to ensure memory safety. The programmer can override its behaviour for a specific ``ref`` or ``ptr`` type ``T``. (Later versions of the language may weaken this restriction.) @@ -103,7 +125,7 @@ language may weaken this restriction.) The signature has to be: .. code-block:: nim - proc deepCopy(x: T): T {.override.} + proc `=deepCopy`(x: T): T This mechanism is used by most data structures that support shared memory like channels to implement thread safe automatic memory management. diff --git a/doc/manual/type_rel.txt b/doc/manual/type_rel.txt index 74539f907..d1593a02e 100644 --- a/doc/manual/type_rel.txt +++ b/doc/manual/type_rel.txt @@ -18,7 +18,7 @@ algorithm (in pseudo-code) determines type equality: incl(s, (a,b)) if a.kind == b.kind: case a.kind - of int, intXX, float, floatXX, char, string, cstring, pointer, + of int, intXX, float, floatXX, char, string, cstring, pointer, bool, nil, void: # leaf type: kinds identical; nothing more to check result = true @@ -61,7 +61,7 @@ with an auxiliary set ``s`` is omitted: proc typeEqualsOrDistinct(a, b: PType): bool = if a.kind == b.kind: case a.kind - of int, intXX, float, floatXX, char, string, cstring, pointer, + of int, intXX, float, floatXX, char, string, cstring, pointer, bool, nil, void: # leaf type: kinds identical; nothing more to check result = true @@ -90,7 +90,7 @@ with an auxiliary set ``s`` is omitted: result = typeEqualsOrDistinct(a.baseType, b) elif b.kind == distinct: result = typeEqualsOrDistinct(a, b.baseType) - + Subtype relation ---------------- @@ -145,7 +145,7 @@ algorithm returns true: A type ``a`` is **explicitly** convertible to type ``b`` iff the following algorithm returns true: - + .. code-block:: nim proc isIntegralType(t: PType): bool = result = isOrdinal(t) or t.kind in {float, float32, float64} @@ -156,8 +156,8 @@ algorithm returns true: if typeEqualsOrDistinct(a, b): return true if isIntegralType(a) and isIntegralType(b): return true if isSubtype(a, b) or isSubtype(b, a): return true - -The convertible relation can be relaxed by a user-defined type + +The convertible relation can be relaxed by a user-defined type `converter`:idx:. .. code-block:: nim @@ -174,7 +174,7 @@ The convertible relation can be relaxed by a user-defined type x = chr.toInt echo x # => 97 -The type conversion ``T(a)`` is an L-value if ``a`` is an L-value and +The type conversion ``T(a)`` is an L-value if ``a`` is an L-value and ``typeEqualsOrDistinct(T, type(a))`` holds. @@ -186,6 +186,157 @@ An expression ``b`` can be assigned to an expression ``a`` iff ``a`` is an Overloading resolution ----------------------- +====================== + +In a call ``p(args)`` the routine ``p`` that matches best is selected. If +multiple routines match equally well, the ambiguity is reported at compiletime. + +Every arg in args needs to match. There are multiple different category how an +argument can match. Let ``f`` be the formal parameter's type and ``a`` the type +of the argument. + +1. Exact match: ``a`` and ``f`` are of the same type. +2. Literal match: ``a`` is an integer literal of value ``v`` + and ``f`` is a signed or unsigned integer type and ``v`` is in ``f``'s + range. Or: ``a`` is a floating point literal of value ``v`` + and ``f`` is a floating point type and ``v`` is in ``f``'s + range. +3. Generic match: ``f`` is a generic type and ``a`` matches, for + instance ``a`` is ``int`` and ``f`` is a generic (constrained) parameter + type (like in ``[T]`` or ``[T: int|char]``. +4. Subrange or subtype match: ``a`` is a ``range[T]`` and ``T`` + matches ``f`` exactly. Or: ``a`` is a subtype of ``f``. +5. Integral conversion match: ``a`` is convertible to ``f`` and ``f`` and ``a`` + is some integer or floating point type. +6. Conversion match: ``a`` is convertible to ``f``, possibly via a user + defined ``converter``. + +These matching categories have a priority: An exact match is better than a +literal match and that is better than a generic match etc. In the following +``count(p, m)`` counts the number of matches of the matching category ``m`` +for the routine ``p``. + +A routine ``p`` matches better than a routine ``q`` if the following +algorithm returns true:: + + for each matching category m in ["exact match", "literal match", + "generic match", "subtype match", + "integral match", "conversion match"]: + if count(p, m) > count(q, m): return true + elif count(p, m) == count(q, m): + discard "continue with next category m" + else: + return false + return "ambiguous" + + +Some examples: + +.. code-block:: nim + proc takesInt(x: int) = echo "int" + proc takesInt[T](x: T) = echo "T" + proc takesInt(x: int16) = echo "int16" + + takesInt(4) # "int" + var x: int32 + takesInt(x) # "T" + var y: int16 + takesInt(y) # "int16" + var z: range[0..4] = 0 + takesInt(z) # "T" + + +If this algorithm returns "ambiguous" further disambiguation is performed: +If the argument ``a`` matches both the parameter type ``f`` of ``p`` +and ``g`` of ``q`` via a subtyping relation, the inheritance depth is taken +into account: + +.. code-block:: nim + type + A = object of RootObj + B = object of A + C = object of B + + proc p(obj: A) = + echo "A" + + proc p(obj: B) = + echo "B" + + var c = C() + # not ambiguous, calls 'B', not 'A' since B is a subtype of A + # but not vice versa: + p(c) + + proc pp(obj: A, obj2: B) = echo "A B" + proc pp(obj: B, obj2: A) = echo "B A" + + # but this is ambiguous: + pp(c, c) + + +Likewise for generic matches the most specialized generic type (that still +matches) is preferred: + +.. code-block:: nim + proc gen[T](x: ref ref T) = echo "ref ref T" + proc gen[T](x: ref T) = echo "ref T" + proc gen[T](x: T) = echo "T" + + var ri: ref int + gen(ri) # "ref T" + + +Overloading based on 'var T' +---------------------------- + +If the formal parameter ``f`` is of type ``var T`` in addition to the ordinary +type checking, the argument is checked to be an `l-value`:idx:. ``var T`` +matches better than just ``T`` then. + + +Automatic dereferencing +----------------------- + +If the `experimental mode <experimental pragma>`_ is active and no other match +is found, the first argument ``a`` is dereferenced automatically if it's a +pointer type and overloading resolution is tried with ``a[]`` instead. + + +Lazy type resolution for expr +----------------------------- + +**Note**: An `unresolved`:idx: expression is an expression for which no symbol +lookups and no type checking have been performed. + +Since templates and macros that are not declared as ``immediate`` participate +in overloading resolution it's essential to have a way to pass unresolved +expressions to a template or macro. This is what the meta-type ``expr`` +accomplishes: + +.. code-block:: nim + template rem(x: expr) = discard + + rem unresolvedExpression(undeclaredIdentifier) + +A parameter of type ``expr`` always matches any argument (as long as there is +any argument passed to it). + +But one has to watch out because other overloads might trigger the +argument's resolution: + +.. code-block:: nim + template rem(x: expr) = discard + proc rem[T](x: T) = discard + + # undeclared identifier: 'unresolvedExpression' + rem unresolvedExpression(undeclaredIdentifier) + +``expr`` is the only metatype that is lazy in this sense, the other +metatypes ``stmt`` and ``typedesc`` are not lazy. + + +Varargs matching +---------------- -To be written. +See `Varargs`_. diff --git a/doc/manual/typedesc.txt b/doc/manual/typedesc.txt index 5087c1204..de1d84d7d 100644 --- a/doc/manual/typedesc.txt +++ b/doc/manual/typedesc.txt @@ -6,7 +6,7 @@ static[T] **Note**: static[T] is still in development. -As their name suggests, static params must be known at compile-time: +As their name suggests, static parameters must be known at compile-time: .. code-block:: nim @@ -23,23 +23,7 @@ As their name suggests, static params must be known at compile-time: For the purposes of code generation, all static params are treated as generic params - the proc will be compiled separately for each unique -supplied value (or combination of values). - -Furthermore, the system module defines a `semistatic[T]` type that can be -used to declare procs accepting both static and run-time values, which can -optimize their body according to the supplied param using the `isStatic(p)` -predicate: - -.. code-block:: nim - - # The following proc will be compiled once for each unique static - # value and also once for the case handling all run-time values: - - proc re(pattern: semistatic[string]): RegEx = - when isStatic(pattern): - result = precompiledRegex(pattern) - else: - result = compile(pattern) +supplied value (or combination of values). Static params can also appear in the signatures of generic types: @@ -61,7 +45,7 @@ typedesc -------- `typedesc` is a special type allowing one to treat types as compile-time values -(i.e. if types are compile-time values and all values have a type, then +(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 @@ -82,9 +66,6 @@ When multiple typedesc params are present, they act like a distinct type class one can use a named alias or an explicit `typedesc` generic param: .. code-block:: nim - - # `type1` and `type2` are aliases for typedesc available from system.nim - proc acceptOnlyTypePairs(A, B: type1; C, D: type2) proc acceptOnlyTypePairs[T: typedesc, U: typedesc](A, B: T; C, D: U) Once bound, typedesc params can appear in the rest of the proc signature: @@ -100,7 +81,7 @@ When used with macros and .compileTime. procs on the other hand, the compiler does not 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. One can create variables, store typedesc -values inside containers and so on. For example, here is how one can create +values inside containers and so on. For example, here is how one can create a type-safe wrapper for the unsafe `printf` function from C: .. code-block:: nim @@ -114,7 +95,7 @@ a type-safe wrapper for the unsafe `printf` function from C: of 's': string of 'p': pointer else: EOutOfRange - + var actualType = args[i].getType inc i @@ -123,7 +104,7 @@ a type-safe wrapper for the unsafe `printf` function from C: 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") diff --git a/doc/manual/types.txt b/doc/manual/types.txt index a20701121..bdf51941d 100644 --- a/doc/manual/types.txt +++ b/doc/manual/types.txt @@ -497,6 +497,24 @@ type conversions in this context: In this example ``$`` is applied to any argument that is passed to the parameter ``a``. (Note that ``$`` applied to strings is a nop.) +Note that an explicit array constructor passed to a ``varargs`` parameter is +not wrapped in another implicit array construction: + +.. code-block:: nim + proc takeV[T](a: varargs[T]) = discard + + takeV([123, 2, 1]) # takeV's T is "int", not "array of int" + + +``varargs[expr]`` is treated specially: It matches a variable list of arguments +of arbitrary type but *always* constructs an implicit array. This is required +so that the builtin ``echo`` proc does what is expected: + +.. code-block:: nim + proc echo*(x: varargs[expr, `$`]) {...} + + echo(@[1, 2, 3]) + # prints "@[1, 2, 3]" and not "123" Tuples and object types @@ -550,7 +568,7 @@ the ``of`` operator can be used to determine the object's type. name*: string # the * means that `name` is accessible from other modules age: int # no * means that the field is hidden - Student = object of Person # a student is a person + Student = ref object of Person # a student is a person id: int # with an id field var @@ -695,7 +713,7 @@ via ``{.experimental.}``: new(n) echo n.depth # no need to write n[].depth either - + In order to simplify structural type checking, recursive tuples are not valid: @@ -846,7 +864,9 @@ Future directions: * Builtin regions like ``private``, ``global`` and ``local`` will prove very useful for the upcoming OpenCL target. * Builtin "regions" can model ``lent`` and ``unique`` pointers. - +* An assignment operator can be attached to a region so that proper write + barriers can be generated. This would imply that the GC can be implemented + completely in user-space. Procedural type diff --git a/doc/nimc.txt b/doc/nimc.txt index c6b0b5255..831fce567 100644 --- a/doc/nimc.txt +++ b/doc/nimc.txt @@ -545,6 +545,20 @@ instead: let x = newFoo(3, 4) +Wrapping constructors +~~~~~~~~~~~~~~~~~~~~~ + +Sometimes a C++ class has a private copy constructor and so code like +``Class c = Class(1,2);`` must not be generated but instead ``Class c(1,2);``. +For this purpose the Nim proc that wraps a C++ constructor needs to be +annotated with the `constructor`:idx: pragma. This pragma also helps to generate +faster C++ code since construction then doesn't invoke the copy constructor: + +.. code-block:: nim + # a better constructor of 'Foo': + proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)", constructor.} + + Wrapping destructors ~~~~~~~~~~~~~~~~~~~~ @@ -608,7 +622,7 @@ allows *sloppy* interfacing with libraries written in Objective C: - (void)greet:(long)x y:(long)dummy { - printf("Hello, World!\n"); + printf("Hello, World!\n"); } @end diff --git a/doc/tut2.txt b/doc/tut2.txt index 4d30b1445..e1ac20074 100644 --- a/doc/tut2.txt +++ b/doc/tut2.txt @@ -56,12 +56,12 @@ Objects have access to their type at runtime. There is an .. code-block:: nim type - Person = object of RootObj + Person = ref object of RootObj name*: string # the * means that `name` is accessible from other modules age: int # no * means that the field is hidden from other modules - Student = object of Person # Student inherits from Person - id: int # with an id field + Student = ref object of Person # Student inherits from Person + id: int # with an id field var student: Student @@ -69,6 +69,7 @@ Objects have access to their type at runtime. There is an assert(student of Student) # is true # object construction: student = Student(name: "Anton", age: 5, id: 2) + echo student[] Object fields that should be visible from outside the defining module have to be marked by ``*``. In contrast to tuples, different object types are @@ -82,6 +83,9 @@ no ancestor are implicitly ``final``. You can use the ``inheritable`` pragma to introduce new object roots apart from ``system.RootObj``. (This is used in the GTK wrapper for instance.) +Ref objects should be used whenever inheritance is used. It isn't strictly +necessary, but with non-ref objects assignments such as ``let person: Person = +Student(id: 123)`` will truncate subclass fields. **Note**: Composition (*has-a* relation) is often preferable to inheritance (*is-a* relation) for simple code reuse. Since objects are value types in @@ -228,7 +232,7 @@ is needed: .. code-block:: nim type - Socket* = object of RootObj + Socket* = ref object of RootObj FHost: int # cannot be accessed from the outside of the module # the `F` prefix is a convention to avoid clashes since # the accessors are named `host` @@ -241,8 +245,8 @@ is needed: ## getter of hostAddr s.FHost - var - s: Socket + var s: Socket + new s s.host = 34 # same as `host=`(s, 34) (The example also shows ``inline`` procedures.) @@ -313,8 +317,8 @@ dispatching: .. code-block:: nim type - Thing = object of RootObj - Unit = object of Thing + Thing = ref object of RootObj + Unit = ref object of Thing x: int method collide(a, b: Thing) {.inline.} = @@ -326,8 +330,9 @@ dispatching: method collide(a: Unit, b: Thing) {.inline.} = echo "2" - var - a, b: Unit + var a, b: Unit + new a + new b collide(a, b) # output: 2 |