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 *overridden* instead of *overloaded*. This means the
implementation is automatically lifted to structured types. For instance if type
``T`` has an overridden 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 overridden ``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
``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



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

``=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
    MyObj = object
      x, y: int
      p: pointer

  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.

  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`:idx:
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

This mechanism will be 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.
