documented object constrs; endb works again

This commit is contained in:
Araq 2013-03-09 20:43:56 +01:00
commit a64d4dc35c
11 changed files with 152 additions and 143 deletions

View file

@ -984,7 +984,7 @@ in future versions of the compiler.
.. code-block:: nimrod
type
TPerson = tuple[name: string, age: int] # type representing a person
TPerson = tuple[name: string, age: int] # type representing a person:
# a person consists of a name
# and an age
var
@ -1000,7 +1000,6 @@ For consistency with ``object`` declarations, tuples in a ``type`` section
can also be defined with indentation instead of ``[]``:
.. code-block:: nimrod
type
TPerson = tuple # type representing a person
name: string # a person consists of a name
@ -1011,7 +1010,6 @@ and information hiding. Objects have access to their type at runtime, so that
the ``of`` operator can be used to determine the object's type.
.. code-block:: nimrod
type
TPerson {.inheritable.} = object
name*: string # the * means that `name` is accessible from other modules
@ -1032,6 +1030,19 @@ and thus have no hidden type field. One can use the ``inheritable`` pragma to
introduce new object roots apart from ``system.TObject``.
Object construction
-------------------
Objects can also be created with an `object construction expression`:idx: that
has the syntax ``T(fieldA: valueA, fieldB: valueB, ...)`` where ``T`` is
an ``object`` type or a ``ref object`` type:
.. code-block:: nimrod
var student = TStudent(name: "Anton", age: 5, id: 3)
For a ``ref object`` type ``new`` is invoked implicitly.
Object variants
---------------
Often an object hierarchy is overkill in certain situations where simple
@ -1061,15 +1072,22 @@ An example:
of nkIf:
condition, thenPart, elsePart: PNode
var
n: PNode
new(n) # creates a new node
n.kind = nkFloat
n.floatVal = 0.0 # valid, because ``n.kind==nkFloat``, so that it fits
# create a new case object:
var n = PNode(kind: nkIf, condition: nil)
# accessing n.thenPart is valid because the ``nkIf`` branch is active:
n.thenPart = PNode(kind: nkFloat, floatVal: 2.0)
# the following statement raises an `EInvalidField` exception, because
# n.kind's value does not fit:
# n.kind's value does not fit and the ``nkString`` branch is not active:
n.strVal = ""
# invalid: would change the active object branch:
n.kind = nkInt
var x = PNode(kind: nkAdd, leftOp: PNode(kind: nkInt, intVal: 4),
rightOp: PNode(kind: nkInt, intVal: 2))
# valid: does not change the active object branch:
x.kind = nkSub
As can been seen from the example, an advantage to an object hierarchy is that
no casting between different object types is needed. Yet, access to invalid
@ -1078,6 +1096,11 @@ object fields raises an exception.
The syntax of ``case`` in an object declaration follows closely the syntax of
the ``case`` statement: The branches in a ``case`` section may be indented too.
In the example the ``kind`` field is called the `discriminator`:idx:\: For
safety its address cannot be taken and assignments to it are restricted: The
new value must not lead to a change of the active object branch. For an object
branch switch ``system.reset`` has to be used.
Set type
--------
@ -2387,6 +2410,7 @@ the proc's name.
Procs as expressions can appear both as nested procs and inside top level
executable code.
Do notation
-----------
@ -2410,7 +2434,7 @@ Again, let's see the equivalent of the previous example:
sort(cities) do (x,y: string) -> int:
cmp(x.len, y.len)
Finally, more than one ``do`` blocks can appear in a single call:
Finally, more than one ``do`` block can appear in a single call:
.. code-block:: nimrod
proc performWithUndo(task: proc(), undo: proc()) = ...
@ -2426,6 +2450,7 @@ 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
------------------------
@ -2987,8 +3012,7 @@ possibly raised exceptions; the algorithm operates on ``p``'s call graph:
raise ``system.E_Base`` unless ``q`` has an explicit ``raises`` list.
3. Every call to a method ``m`` is assumed to
raise ``system.E_Base`` unless ``m`` has an explicit ``raises`` list.
4. For every other call the analysis can determine an
exact ``raises`` list.
4. For every other call the analysis can determine an exact ``raises`` list.
5. For determining a ``raises`` list, the ``raise`` and ``try`` statements
of ``p`` are taken into consideration.
@ -3259,7 +3283,7 @@ Symbol lookup in generics
The symbol binding rules in generics are slightly subtle: There are "open" and
"closed" symbols. A "closed" symbol cannot be re-bound in the instantiation
context, an "open" symbol can be. Per default overloaded symbols are open
context, an "open" symbol can. Per default overloaded symbols are open
and every other symbol is closed.
Open symbols are looked up in two different contexts: Both the context
@ -4106,8 +4130,8 @@ implemented with term rewriting:
proc p(x, y: int; cond: bool): int =
result = if cond: x + y else: x - y
template optP{p(x, y, true)}(x, y: expr): expr = x + y
template optP{p(x, y, false)}(x, y: expr): expr = x - y
template optP1{p(x, y, true)}(x, y: expr): expr = x + y
template optP2{p(x, y, false)}(x, y: expr): expr = x - y
Example: hoisting

View file

@ -46,8 +46,7 @@ Objects
Like tuples, objects are a means to pack different values together in a
structured way. However, objects provide many features that tuples do not:
They provide inheritance and information hiding. Because objects encapsulate
data, the ``()`` tuple constructor cannot be used to construct objects. So
the order of the object's fields is not as important as it is for tuples. The
data, the ``T()`` object constructor should only be used internally and the
programmer should provide a proc to initialize the object (this is called
a *constructor*).
@ -55,7 +54,6 @@ Objects have access to their type at runtime. There is an
``of`` operator that can be used to check the object's type:
.. code-block:: nimrod
type
TPerson = object of TObject
name*: string # the * means that `name` is accessible from other modules
@ -68,6 +66,8 @@ Objects have access to their type at runtime. There is an
student: TStudent
person: TPerson
assert(student of TStudent) # is true
# object construction:
student = TStudent(name: "Anton", age: 5, id: 2)
Object fields that should be visible from outside the defining module have to
be marked by ``*``. In contrast to tuples, different object types are
@ -161,12 +161,7 @@ An example:
of nkIf:
condition, thenPart, elsePart: PNode
var
n: PNode
new(n) # creates a new node
n.kind = nkFloat
n.floatVal = 0.0 # valid, because ``n.kind==nkFloat``
var n = PNode(kind: nkFloat, floatVal: 1.0)
# the following statement raises an `EInvalidField` exception, because
# n.kind's value does not fit:
n.strVal = ""
@ -288,30 +283,22 @@ Procedures always use static dispatch. For dynamic dispatch replace the
.. code-block:: nimrod
type
TExpr = object of TObject ## abstract base class for an expression
TLiteral = object of TExpr
PExpr = ref object of TObject ## abstract base class for an expression
PLiteral = ref object of PExpr
x: int
TPlusExpr = object of TExpr
a, b: ref TExpr
method eval(e: ref TExpr): int =
PPlusExpr = ref object of PExpr
a, b: PExpr
# watch out: 'eval' relies on dynamic binding
method eval(e: PExpr): int =
# override this base method
quit "to override!"
method eval(e: ref TLiteral): int = return e.x
method eval(e: ref TPlusExpr): int =
# watch out: relies on dynamic binding
return eval(e.a) + eval(e.b)
method eval(e: PLiteral): int = e.x
method eval(e: PPlusExpr): int = eval(e.a) + eval(e.b)
proc newLit(x: int): ref TLiteral =
new(result)
result.x = x
proc newPlus(a, b: ref TExpr): ref TPlusExpr =
new(result)
result.a = a
result.b = b
proc newLit(x: int): PLiteral = PLiteral(x: x)
proc newPlus(a, b: PExpr): PPlusExpr = PPlusExpr(a: a, b: b)
echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4)))