From b853d7a4f8e681bd7cd5f038f1bda2351f6c3e4a Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 1 Jun 2019 14:55:34 +0200 Subject: [PATCH] Created Destructors, 2nd edition (rest) --- Destructors,-2nd-edition.rest | 435 ++++++++++++++++++++++++++++++++++ 1 file changed, 435 insertions(+) create mode 100644 Destructors,-2nd-edition.rest diff --git a/Destructors,-2nd-edition.rest b/Destructors,-2nd-edition.rest new file mode 100644 index 0000000..e80e4e2 --- /dev/null +++ b/Destructors,-2nd-edition.rest @@ -0,0 +1,435 @@ +================================== +Nim Destructors and Move Semantics +================================== + +:Authors: Andreas Rumpf +:Version: |nimversion| + +.. contents:: + + +About this document +=================== + +This document describes the upcoming Nim runtime which does +not use classical GC algorithms anymore but is based on destructors and +move semantics. The new runtime's advantages are that Nim programs become +oblivious to the involved heap sizes and programs are easier to write to make +effective use of multi-core machines. As a nice bonus, files and sockets and +the like will not require manual ``close`` calls anymore. + +This document aims to be a precise specification about how +move semantics and destructors work in Nim. + + +Motivating example +================== + +With the language mechanisms described here a custom seq could be +written as: + +.. code-block:: nim + + type + myseq*[T] = object + len, cap: int + data: ptr UncheckedArray[T] + + proc `=destroy`*[T](x: var myseq[T]) = + if x.data != nil: + for i in 0..= x.cap: resize(x) + x.data[x.len] = y + inc x.len + + proc `[]`*[T](x: myseq[T]; i: Natural): lent T = + assert i < x.len + x.data[i] + + proc `[]=`*[T](x: myseq[T]; i: Natural; y: sink T) = + assert i < x.len + x.data[i] = y + + proc createSeq*[T](elems: varargs[T]): myseq[T] = + result.cap = elems.len + result.len = elems.len + result.data = cast[type(result.data)](alloc(result.cap * sizeof(T))) + for i in 0.. 0: + yield it + + +Owned refs +========== + +Let ``W`` be an ``owned ref`` type. Conceptually its hooks look like: + +.. code-block:: nim + + proc `=destroy`(x: var W) = + if x != nil: + assert x.refcount == 0, "dangling unowned pointers exist!" + `=destroy`(x[]) + x = nil + + proc `=`(x: var W; y: W) {.error: "owned refs can only be moved".} + + proc `=move`(x, y: var W) = + if x != y: + `=destroy`(x) + bitwiseCopy x, y # raw pointer copy + y = nil + +Let ``U`` be an unowned ``ref`` type. Conceptually its hooks look like: + +.. code-block:: nim + + proc `=destroy`(x: var U) = + if x != nil: + dec x.refcount + + proc `=`(x: var U; y: U) = + # Note: No need to check for self-assignments here. + if y != nil: inc y.refcount + if x != nil: dec x.refcount + bitwiseCopy x, y # raw pointer copy + + proc `=move`(x, y: var U) = + # Note: Moves are the same as assignments. + `=`(x, y) +