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