Merge pull request #2789 from ozra/devel
Change wording in some parts. Fix some typos.
This commit is contained in:
commit
11bd7ef5e8
11 changed files with 94 additions and 65 deletions
|
|
@ -1,15 +1,15 @@
|
||||||
About this document
|
About this document
|
||||||
===================
|
===================
|
||||||
|
|
||||||
**Note**: This document is a draft! Several of Nim's features need more
|
**Note**: This document is a draft! Several of Nim's features may need more
|
||||||
precise wording. This manual will evolve into a proper specification some
|
precise wording. This manual is constantly evolving until the 1.0 release and is
|
||||||
day.
|
not to be considered as the final proper specification.
|
||||||
|
|
||||||
This document describes the lexis, the syntax, and the semantics of Nim.
|
This document describes the lexis, the syntax, and the semantics of Nim.
|
||||||
|
|
||||||
The language constructs are explained using an extended BNF, in
|
The language constructs are explained using an extended BNF, in which ``(a)*``
|
||||||
which ``(a)*`` means 0 or more ``a``'s, ``a+`` means 1 or more ``a``'s, and
|
means 0 or more ``a``'s, ``a+`` means 1 or more ``a``'s, and ``(a)?`` means an
|
||||||
``(a)?`` means an optional *a*. Parentheses may be used to group elements.
|
optional *a*. Parentheses may be used to group elements.
|
||||||
|
|
||||||
``&`` is the lookahead operator; ``&a`` means that an ``a`` is expected but
|
``&`` is the lookahead operator; ``&a`` means that an ``a`` is expected but
|
||||||
not consumed. It will be consumed in the following rule.
|
not consumed. It will be consumed in the following rule.
|
||||||
|
|
@ -33,5 +33,5 @@ and ``a ^* b`` is short for ``(a (b a)*)?``. Example::
|
||||||
arrayConstructor = '[' expr ^* ',' ']'
|
arrayConstructor = '[' expr ^* ',' ']'
|
||||||
|
|
||||||
Other parts of Nim - like scoping rules or runtime semantics are only
|
Other parts of Nim - like scoping rules or runtime semantics are only
|
||||||
described in an informal manner for now.
|
described in the, more easily comprehensible, informal manner for now.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ exceptions* or *dying with a fatal error*. However, the implementation
|
||||||
provides a means to disable these runtime checks. See the section pragmas_
|
provides a means to disable these runtime checks. See the section pragmas_
|
||||||
for details.
|
for details.
|
||||||
|
|
||||||
Wether a checked runtime error results in an exception or in a fatal error at
|
Whether a checked runtime error results in an exception or in a fatal error at
|
||||||
runtime is implementation specific. Thus the following program is always
|
runtime is implementation specific. Thus the following program is always
|
||||||
invalid:
|
invalid:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ possibly raised exceptions; the algorithm operates on ``p``'s call graph:
|
||||||
However if the call is of the form ``f(...)`` where ``f`` is a parameter
|
However if the call is of the form ``f(...)`` where ``f`` is a parameter
|
||||||
of the currently analysed routine it is ignored. The call is optimistically
|
of the currently analysed routine it is ignored. The call is optimistically
|
||||||
assumed to have no effect. Rule 2 compensates for this case.
|
assumed to have no effect. Rule 2 compensates for this case.
|
||||||
2. Every expression of some proc type wihtin a call that is not a call
|
2. Every expression of some proc type within a call that is not a call
|
||||||
itself (and not nil) is assumed to be called indirectly somehow and thus
|
itself (and not nil) is assumed to be called indirectly somehow and thus
|
||||||
its raises list is added to ``p``'s raises list.
|
its raises list is added to ``p``'s raises list.
|
||||||
3. Every call to a proc ``q`` which has an unknown body (due to a forward
|
3. Every call to a proc ``q`` which has an unknown body (due to a forward
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ underscores ``__`` are not allowed::
|
||||||
digit ::= '0'..'9'
|
digit ::= '0'..'9'
|
||||||
IDENTIFIER ::= letter ( ['_'] (letter | digit) )*
|
IDENTIFIER ::= letter ( ['_'] (letter | digit) )*
|
||||||
|
|
||||||
Currently any unicode character with an ordinal value > 127 (non ASCII) is
|
Currently any Unicode character with an ordinal value > 127 (non ASCII) is
|
||||||
classified as a ``letter`` and may thus be part of an identifier but later
|
classified as a ``letter`` and may thus be part of an identifier but later
|
||||||
versions of the language may assign some Unicode characters to belong to the
|
versions of the language may assign some Unicode characters to belong to the
|
||||||
operator characters instead.
|
operator characters instead.
|
||||||
|
|
|
||||||
|
|
@ -178,8 +178,7 @@ Module scope
|
||||||
~~~~~~~~~~~~
|
~~~~~~~~~~~~
|
||||||
All identifiers of a module are valid from the point of declaration until
|
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*
|
the end of the module. Identifiers from indirectly dependent modules are *not*
|
||||||
available. The `system`:idx: module is automatically imported in every other
|
available. The `system`:idx: module is automatically imported in every module.
|
||||||
module.
|
|
||||||
|
|
||||||
If a module imports an identifier by two different modules, each occurrence of
|
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
|
the identifier has to be qualified, unless it is an overloaded procedure or
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,7 @@ The deprecated pragma is used to mark a symbol as deprecated:
|
||||||
proc p() {.deprecated.}
|
proc p() {.deprecated.}
|
||||||
var x {.deprecated.}: char
|
var x {.deprecated.}: char
|
||||||
|
|
||||||
It can also be used as a statement. Then it takes a list of *renamings*. The
|
It can also be used as a statement, in that case it takes a list of *renamings*.
|
||||||
upcoming ``nimfix`` tool can automatically update the code and perform these
|
|
||||||
renamings:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
type
|
type
|
||||||
|
|
@ -28,6 +26,9 @@ renamings:
|
||||||
Stream = ref object
|
Stream = ref object
|
||||||
{.deprecated: [TFile: File, PStream: Stream].}
|
{.deprecated: [TFile: File, PStream: Stream].}
|
||||||
|
|
||||||
|
The ``nimfix`` tool can be used to, without effort, automatically update your
|
||||||
|
code and refactor it by performing these renamings.
|
||||||
|
|
||||||
|
|
||||||
noSideEffect pragma
|
noSideEffect pragma
|
||||||
-------------------
|
-------------------
|
||||||
|
|
@ -54,9 +55,7 @@ destructor pragma
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
The ``destructor`` pragma is used to mark a proc to act as a type destructor.
|
The ``destructor`` pragma is used to mark a proc to act as a type destructor.
|
||||||
Its usage is deprecated, use the ``override`` pragma instead.
|
Its usage is deprecated, See `type bound operations`_ instead.
|
||||||
See `type bound operations`_.
|
|
||||||
|
|
||||||
|
|
||||||
override pragma
|
override pragma
|
||||||
---------------
|
---------------
|
||||||
|
|
@ -371,7 +370,7 @@ The ``register`` pragma is for variables only. It declares the variable as
|
||||||
in a hardware register for faster access. C compilers usually ignore this
|
in a hardware register for faster access. C compilers usually ignore this
|
||||||
though and for good reasons: Often they do a better job without it anyway.
|
though and for good reasons: Often they do a better job without it anyway.
|
||||||
|
|
||||||
In highly specific cases (a dispatch loop of an bytecode interpreter for
|
In highly specific cases (a dispatch loop of a bytecode interpreter for
|
||||||
example) it may provide benefits, though.
|
example) it may provide benefits, though.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -429,13 +428,13 @@ Example:
|
||||||
2. When a top level call is encountered (usually at the very end of the module),
|
2. When a top level call is encountered (usually at the very end of the module),
|
||||||
the compiler will try to determine the actual types of all of the symbols in the
|
the compiler will try to determine the actual types of all of the symbols in the
|
||||||
matching overload set. This is a potentially recursive process as the signatures
|
matching overload set. This is a potentially recursive process as the signatures
|
||||||
of the symbols may include other call expressions, whoose types will be resolved
|
of the symbols may include other call expressions, whose types will be resolved
|
||||||
at this point too.
|
at this point too.
|
||||||
|
|
||||||
3. Finally, after the best overload is picked, the compiler will start compiling
|
3. Finally, after the best overload is picked, the compiler will start
|
||||||
the body of the respective symbol. This in turn will lead the compiler to discover
|
compiling the body of the respective symbol. This in turn will lead the
|
||||||
more call expresions that need to be resolved and steps 2 and 3 will be repeated
|
compiler to discover more call expressions that need to be resolved and steps
|
||||||
as necessary.
|
2 and 3 will be repeated as necessary.
|
||||||
|
|
||||||
Please note that if a callable symbol is never used in this scenario, its body
|
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
|
will never be compiled. This is the default behavior leading to best compilation
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,46 @@ Procedures
|
||||||
==========
|
==========
|
||||||
|
|
||||||
What most programming languages call `methods`:idx: or `functions`:idx: are
|
What most programming languages call `methods`:idx: or `functions`:idx: are
|
||||||
called `procedures`:idx: in Nim (which is the correct terminology). A
|
called `procedures`:idx: in Nim (which is the correct terminology). A procedure
|
||||||
procedure declaration defines an identifier and associates it with a block
|
declaration consists of an identifier, zero or more formal parameters, a return
|
||||||
of code.
|
value type and a block of code. Formal parameters are declared as a list of
|
||||||
A procedure may call itself recursively. A parameter may be given a default
|
identifiers separated by either comma or semicolon. A parameter is given a type
|
||||||
value that is used if the caller does not provide a value for this parameter.
|
by ``: typename``. The type applies to all parameters immediately before it,
|
||||||
|
until either the beginning of the parameter list, a semicolon separator or an
|
||||||
|
already typed parameter, is reached. The semicolon can be used to make
|
||||||
|
separation of types and subsequent identifiers more distinct.
|
||||||
|
|
||||||
If the proc declaration has no body, it is a `forward`:idx: declaration. If
|
.. code-block:: nim
|
||||||
the proc returns a value, the procedure body can access an implicitly declared
|
# Using only commas
|
||||||
|
proc foo(a, b: int, c, d: bool): int
|
||||||
|
|
||||||
|
# Using semicolon for visual distinction
|
||||||
|
proc foo(a, b: int; c, d: bool): int
|
||||||
|
|
||||||
|
# Will fail: a is untyped since ';' stops type propagation.
|
||||||
|
proc foo(a; b: int; c, d: bool): int
|
||||||
|
|
||||||
|
A parameter may be declared with a default value which is used if the caller
|
||||||
|
does not provide a value for the argument.
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
# b is optional with 47 as its default value
|
||||||
|
proc foo(a: int, b: int = 47): int
|
||||||
|
|
||||||
|
Parameters can be declared mutable and so allow the proc to modify those
|
||||||
|
arguments, by using the type modifier `var`.
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
# "returning" a value to the caller through the 2nd argument
|
||||||
|
# Notice that the function uses no actual return value at all (ie void)
|
||||||
|
proc foo(inp: int, outp: var int) =
|
||||||
|
outp = inp + 47
|
||||||
|
|
||||||
|
If the proc declaration has no body, it is a `forward`:idx: declaration. If the
|
||||||
|
proc returns a value, the procedure body can access an implicitly declared
|
||||||
variable named `result`:idx: that represents the return value. Procs can be
|
variable named `result`:idx: that represents the return value. Procs can be
|
||||||
overloaded. The overloading resolution algorithm tries to find the proc that is
|
overloaded. The overloading resolution algorithm determines which proc is the
|
||||||
the best match for the arguments. Example:
|
best match for the arguments. Example:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
|
|
||||||
|
|
@ -41,9 +70,8 @@ Calling a procedure can be done in many different ways:
|
||||||
# call as a command statement: no () needed:
|
# call as a command statement: no () needed:
|
||||||
callme 0, 1, "abc", '\t'
|
callme 0, 1, "abc", '\t'
|
||||||
|
|
||||||
|
A procedure may call itself recursively.
|
||||||
|
|
||||||
A procedure cannot modify its parameters (unless the parameters have the type
|
|
||||||
`var`).
|
|
||||||
|
|
||||||
`Operators`:idx: are procedures with a special operator symbol as identifier:
|
`Operators`:idx: are procedures with a special operator symbol as identifier:
|
||||||
|
|
||||||
|
|
@ -475,7 +503,7 @@ If the for loop has exactly 2 variables, a ``pairs`` iterator is implicitly
|
||||||
invoked.
|
invoked.
|
||||||
|
|
||||||
Symbol lookup of the identifiers ``items``/``pairs`` is performed after
|
Symbol lookup of the identifiers ``items``/``pairs`` is performed after
|
||||||
the rewriting step, so that all overloadings of ``items``/``pairs`` are taken
|
the rewriting step, so that all overloads of ``items``/``pairs`` are taken
|
||||||
into account.
|
into account.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -511,11 +539,12 @@ Closure iterators have other restrictions than inline iterators:
|
||||||
|
|
||||||
1. ``yield`` in a closure iterator can not occur in a ``try`` statement.
|
1. ``yield`` in a closure iterator can not occur in a ``try`` statement.
|
||||||
2. For now, a closure iterator cannot be evaluated at compile time.
|
2. For now, a closure iterator cannot be evaluated at compile time.
|
||||||
3. ``return`` is allowed in a closure iterator (but rarely useful).
|
3. ``return`` is allowed in a closure iterator (but rarely useful) and ends
|
||||||
4. Both inline and closure iterators cannot be recursive.
|
iteration.
|
||||||
|
4. Neither inline nor closure iterators can be recursive.
|
||||||
|
|
||||||
Iterators that are neither marked ``{.closure.}`` nor ``{.inline.}`` explicitly
|
Iterators that are neither marked ``{.closure.}`` nor ``{.inline.}`` explicitly
|
||||||
default to being inline, but that this may change in future versions of the
|
default to being inline, but this may change in future versions of the
|
||||||
implementation.
|
implementation.
|
||||||
|
|
||||||
The ``iterator`` type is always of the calling convention ``closure``
|
The ``iterator`` type is always of the calling convention ``closure``
|
||||||
|
|
@ -612,8 +641,8 @@ parameters of an outer factory proc:
|
||||||
Implicit return type
|
Implicit return type
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
Since inline interators must always produce values that will be consumed in
|
Since inline iterators must always produce values that will be consumed in
|
||||||
a for loop, the compiler will implicity use the ``auto`` return type if no
|
a for loop, the compiler will implicitly use the ``auto`` return type if no
|
||||||
type is given by the user. In contrast, since closure iterators can be used
|
type is given by the user. In contrast, since closure iterators can be used
|
||||||
as a collaborative tasking system, ``void`` is a valid return type for them.
|
as a collaborative tasking system, ``void`` is a valid return type for them.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ Statements are separated into `simple statements`:idx: and
|
||||||
Simple statements are statements that cannot contain other statements like
|
Simple statements are statements that cannot contain other statements like
|
||||||
assignments, calls or the ``return`` statement; complex statements can
|
assignments, calls or the ``return`` statement; complex statements can
|
||||||
contain other statements. To avoid the `dangling else problem`:idx:, complex
|
contain other statements. To avoid the `dangling else problem`:idx:, complex
|
||||||
statements always have to be intended. The details can be found in the grammar.
|
statements always have to be indented. The details can be found in the grammar.
|
||||||
|
|
||||||
|
|
||||||
Statement list expression
|
Statement list expression
|
||||||
|
|
@ -229,22 +229,18 @@ the expression after the ``elif`` is evaluated (if there is an
|
||||||
``elif`` branch), if it is true the corresponding statements after
|
``elif`` branch), if it is true the corresponding statements after
|
||||||
the ``:`` are executed. This goes on until the last ``elif``. If all
|
the ``:`` are executed. This goes on until the last ``elif``. If all
|
||||||
conditions fail, the ``else`` part is executed. If there is no ``else``
|
conditions fail, the ``else`` part is executed. If there is no ``else``
|
||||||
part, execution continues with the statement after the ``if`` statement.
|
part, execution continues with the next statement.
|
||||||
|
|
||||||
The scoping for an ``if`` statement is slightly subtle to support an important
|
In ``if`` statements new scopes begin immediately after the ``if``/``elif``/``else`` keywords and ends after the corresponding *then* block.
|
||||||
use case. A new scope starts for the ``if``/``elif`` condition and ends after
|
For visualization purposes the scopes have been enclosed in ``{| |}`` in the following example:
|
||||||
the corresponding *then* block:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
if {| (let m = input =~ re"(\w+)=\w+"; m.isMatch):
|
if {| (let m = input =~ re"(\w+)=\w+"; m.isMatch):
|
||||||
echo "key ", m[0], " value ", m[1] |}
|
echo "key ", m[0], " value ", m[1] |}
|
||||||
elif {| (let m = input =~ re""; m.isMatch):
|
elif {| (let m = input =~ re""; m.isMatch):
|
||||||
echo "new m in this scope" |}
|
echo "new m in this scope" |}
|
||||||
else:
|
else: {|
|
||||||
# 'm' not declared here
|
echo "m not declared here" |}
|
||||||
|
|
||||||
In the example the scopes have been enclosed in ``{| |}``.
|
|
||||||
|
|
||||||
|
|
||||||
Case statement
|
Case statement
|
||||||
--------------
|
--------------
|
||||||
|
|
@ -601,7 +597,7 @@ A table constructor is syntactic sugar for an array constructor:
|
||||||
|
|
||||||
The empty table can be written ``{:}`` (in contrast to the empty set
|
The empty table can be written ``{:}`` (in contrast to the empty set
|
||||||
which is ``{}``) which is thus another way to write as the empty array
|
which is ``{}``) which is thus another way to write as the empty array
|
||||||
constructor ``[]``. This slightly unusal way of supporting tables
|
constructor ``[]``. This slightly unusual way of supporting tables
|
||||||
has lots of advantages:
|
has lots of advantages:
|
||||||
|
|
||||||
* The order of the (key,value)-pairs is preserved, thus it is easy to
|
* The order of the (key,value)-pairs is preserved, thus it is easy to
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,10 @@ Fortunately Nim supports side effect analysis:
|
||||||
|
|
||||||
echo f() * 2 # not optimized ;-)
|
echo f() * 2 # not optimized ;-)
|
||||||
|
|
||||||
|
You can make one overload matching with a constraint and one without, and the
|
||||||
|
one with a constraint will have precedence, and so you can handle both cases
|
||||||
|
differently.
|
||||||
|
|
||||||
So what about ``2 * a``? We should tell the compiler ``*`` is commutative. We
|
So what about ``2 * a``? We should tell the compiler ``*`` is commutative. We
|
||||||
cannot really do that however as the following code only swaps arguments
|
cannot really do that however as the following code only swaps arguments
|
||||||
blindly:
|
blindly:
|
||||||
|
|
@ -105,8 +109,10 @@ Predicate Meaning
|
||||||
with the marked parameter.
|
with the marked parameter.
|
||||||
=================== =====================================================
|
=================== =====================================================
|
||||||
|
|
||||||
|
Predicates that share their name with a keyword have to be escaped with
|
||||||
|
backticks: `` `const` ``.
|
||||||
The ``alias`` and ``noalias`` predicates refer not only to the matching AST,
|
The ``alias`` and ``noalias`` predicates refer not only to the matching AST,
|
||||||
but also to every other bound parameter; syntactially they need to occur after
|
but also to every other bound parameter; syntactically they need to occur after
|
||||||
the ordinary AST predicates:
|
the ordinary AST predicates:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
|
|
@ -144,7 +150,7 @@ constant folding, so the following does not work:
|
||||||
|
|
||||||
The reason is that the compiler already transformed the 1 into "1" for
|
The reason is that the compiler already transformed the 1 into "1" for
|
||||||
the ``echo`` statement. However, a term rewriting macro should not change the
|
the ``echo`` statement. However, a term rewriting macro should not change the
|
||||||
semantics anyway. In fact they can be deactived with the ``--patterns:off``
|
semantics anyway. In fact they can be deactivated with the ``--patterns:off``
|
||||||
command line option or temporarily with the ``patterns`` pragma.
|
command line option or temporarily with the ``patterns`` pragma.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -345,15 +351,15 @@ optimization for types that have copying semantics:
|
||||||
## puts a (key, value)-pair into `t`. The semantics of string require
|
## puts a (key, value)-pair into `t`. The semantics of string require
|
||||||
## a copy here:
|
## a copy here:
|
||||||
let idx = findInsertionPosition(key)
|
let idx = findInsertionPosition(key)
|
||||||
t[idx] = key
|
t[idx].key = key
|
||||||
t[idx] = val
|
t[idx].val = val
|
||||||
|
|
||||||
proc `[]=`*(t: var Table, key: string{call}, val: string{call}) =
|
proc `[]=`*(t: var Table, key: string{call}, val: string{call}) =
|
||||||
## puts a (key, value)-pair into `t`. Optimized version that knows that
|
## puts a (key, value)-pair into `t`. Optimized version that knows that
|
||||||
## the strings are unique and thus don't need to be copied:
|
## the strings are unique and thus don't need to be copied:
|
||||||
let idx = findInsertionPosition(key)
|
let idx = findInsertionPosition(key)
|
||||||
shallowCopy t[idx], key
|
shallowCopy t[idx].key, key
|
||||||
shallowCopy t[idx], val
|
shallowCopy t[idx].val, val
|
||||||
|
|
||||||
var t: Table
|
var t: Table
|
||||||
# overloading resolution ensures that the optimized []= is called here:
|
# overloading resolution ensures that the optimized []= is called here:
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,11 @@ Type equality
|
||||||
-------------
|
-------------
|
||||||
Nim uses structural type equivalence for most types. Only for objects,
|
Nim uses structural type equivalence for most types. Only for objects,
|
||||||
enumerations and distinct types name equivalence is used. The following
|
enumerations and distinct types name equivalence is used. The following
|
||||||
algorithm (in pseudo-code) determines type equality:
|
algorithm, *in pseudo-code*, determines type equality:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
proc typeEqualsAux(a, b: PType,
|
proc typeEqualsAux(a, b: PType,
|
||||||
s: var set[PType * PType]): bool =
|
s: var HashSet[(PType, PType)]): bool =
|
||||||
if (a,b) in s: return true
|
if (a,b) in s: return true
|
||||||
incl(s, (a,b))
|
incl(s, (a,b))
|
||||||
if a.kind == b.kind:
|
if a.kind == b.kind:
|
||||||
|
|
@ -43,7 +43,7 @@ algorithm (in pseudo-code) determines type equality:
|
||||||
a.callingConvention == b.callingConvention
|
a.callingConvention == b.callingConvention
|
||||||
|
|
||||||
proc typeEquals(a, b: PType): bool =
|
proc typeEquals(a, b: PType): bool =
|
||||||
var s: set[PType * PType] = {}
|
var s: HashSet[(PType, PType)] = {}
|
||||||
result = typeEqualsAux(a, b, s)
|
result = typeEqualsAux(a, b, s)
|
||||||
|
|
||||||
Since types are graphs which can have cycles, the above algorithm needs an
|
Since types are graphs which can have cycles, the above algorithm needs an
|
||||||
|
|
|
||||||
|
|
@ -803,7 +803,7 @@ exclude ``nil`` as a valid value with the ``not nil`` annotation:
|
||||||
p(x)
|
p(x)
|
||||||
|
|
||||||
The compiler ensures that every code path initializes variables which contain
|
The compiler ensures that every code path initializes variables which contain
|
||||||
not nilable pointers. The details of this analysis are still to be specified
|
non nilable pointers. The details of this analysis are still to be specified
|
||||||
here.
|
here.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1132,7 +1132,7 @@ that don't. Distinct types provide a means to introduce a new string type
|
||||||
|
|
||||||
|
|
||||||
It is an essential property of abstract types that they **do not** imply a
|
It is an essential property of abstract types that they **do not** imply a
|
||||||
subtype relation between the abtract type and its base type. Explict type
|
subtype relation between the abstract type and its base type. Explicit type
|
||||||
conversions from ``string`` to ``SQL`` are allowed:
|
conversions from ``string`` to ``SQL`` are allowed:
|
||||||
|
|
||||||
.. code-block:: nim
|
.. code-block:: nim
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue