Type bound operators

A type bound operator is a proc or func whose name starts with \= but isn’t an operator (i.e. containing only symbols, such as \==). These are unrelated to setters (see Properties), which instead end in \=. A type bound operator declared for a type applies to the type regardless of whether the operator is in scope (including if it is private).

  1. # foo.nim:
  2. var witness* = 0
  3. type Foo[T] = object
  4. proc initFoo*(T: typedesc): Foo[T] = discard
  5. proc `=destroy`[T](x: var Foo[T]) = witness.inc # type bound operator
  6. # main.nim:
  7. import foo
  8. block:
  9. var a = initFoo(int)
  10. doAssert witness == 0
  11. doAssert witness == 1
  12. block:
  13. var a = initFoo(int)
  14. doAssert witness == 1
  15. `=destroy`(a) # can be called explicitly, even without being in scope
  16. doAssert witness == 2
  17. # will still be called upon exiting scope
  18. doAssert witness == 3

Type bound operators are: \=destroy, \=copy, \=sink, \=trace, \=deepcopy, \=wasMoved, \=dup.

These operations can be overridden instead of overloaded. This means that the implementation is automatically lifted to structured types. For instance, if the 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 distinct or object helper type has to be used for one pointer type.

For more details on some of those procs, see Lifetime-tracking hooks.