Type bound operations
=====================

There are 3 operations that are bound to a type:

1. Assignment
2. Destruction
3. Deep copying for communication between threads

These operations can be *overriden* instead of *overloaded*. This means the
implementation is automatically lifted to structured types. For instance if type
``T`` has an overriden assignment operator ``=`` this operator is also used
for assignments of the type ``seq[T]``. Since these operations are bound to a
type they have to be bound to a nominal type for reasons of simplicity of
implementation: This means an overriden ``deepCopy`` for ``ref T`` is really
bound to ``T`` and not to ``ref T``. This also means that one cannot override
``deepCopy`` for both ``ptr T`` and ``ref T`` at the same time; instead a
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 ``=``.

**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.

``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 
the user has not provided an explicit implementation, a destructor for the
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
can then only be used in *destructible contexts* and as parameters:

.. code-block:: nim
  type
    TMyObj = object
      x, y: int
      p: pointer
      
  proc destroy(o: var TMyObj) {.override.} =
    if o.p != nil: dealloc o.p
    
  proc open: TMyObj =
    result = TMyObj(x: 1, y: 2, p: alloc(3))
 
  proc work(o: TMyObj) =
    echo o.x
    # No destructor invoked here for 'o' as 'o' is a parameter.

  proc main() =
    # destructor automatically invoked at the end of the scope:
    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()

A destructible context is currently only the following:

1. The ``expr`` in ``var x = expr``.
2. The ``expr`` in ``let x = expr``.
3. The ``expr`` in ``return expr``.
4. The ``expr`` in ``result = expr`` where ``result`` is the special symbol
   introduced by the compiler.

These rules ensure that the construction is tied to a variable and can easily
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``
parameter to ``new`` has to be used.

**Note**: Destructors are still experimental and the spec might change
significantly in order to incorporate an escape analysis.


deepCopy
--------

``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.)

The signature has to be:

.. code-block:: nim
  proc deepCopy(x: T): T {.override.}

This mechanism is used by most data structures that support shared memory like
channels to implement thread safe automatic memory management.

The builtin ``deepCopy`` can even clone closures and their environments. See
the documentation of `spawn`_ for details.
