summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorjrfondren <41455523+jrfondren@users.noreply.github.com>2019-05-03 13:03:45 -0500
committerGitHub <noreply@github.com>2019-05-03 13:03:45 -0500
commit8cadeb960597a47a09100bdda05672f177d158d2 (patch)
treeafe59c7bc9f5502801754e0f7fead84552a3d4e6 /lib
parent6dfde0e931176405491987e14969f68d81957730 (diff)
parent515ab81477c1c3e4811c4fbf43a3ff81b87be970 (diff)
downloadNim-8cadeb960597a47a09100bdda05672f177d158d2.tar.gz
Merge branch 'devel' into expand-amb-identifier-output
Diffstat (limited to 'lib')
-rw-r--r--lib/core/macros.nim10
-rw-r--r--lib/core/runtime_v2.nim5
-rw-r--r--lib/core/seqs.nim41
-rw-r--r--lib/impure/db_mysql.nim12
-rw-r--r--lib/impure/db_odbc.nim12
-rw-r--r--lib/impure/db_postgres.nim10
-rw-r--r--lib/impure/db_sqlite.nim12
-rw-r--r--lib/impure/nre.nim21
-rw-r--r--lib/js/asyncjs.nim2
-rw-r--r--lib/pure/asyncdispatch.nim43
-rw-r--r--lib/pure/asyncftpclient.nim6
-rw-r--r--lib/pure/asynchttpserver.nim3
-rw-r--r--lib/pure/asyncmacro.nim2
-rw-r--r--lib/pure/asyncnet.nim8
-rw-r--r--lib/pure/base64.nim1
-rw-r--r--lib/pure/collections/hashcommon.nim68
-rw-r--r--lib/pure/collections/lists.nim18
-rw-r--r--lib/pure/collections/sequtils.nim16
-rw-r--r--lib/pure/collections/setimpl.nim153
-rw-r--r--lib/pure/collections/sets.nim473
-rw-r--r--lib/pure/collections/sharedtables.nim10
-rw-r--r--lib/pure/collections/tableimpl.nim111
-rw-r--r--lib/pure/collections/tables.nim271
-rw-r--r--lib/pure/dynlib.nim4
-rw-r--r--lib/pure/htmlgen.nim3
-rw-r--r--lib/pure/includes/osenv.nim2
-rw-r--r--lib/pure/includes/oserr.nim2
-rw-r--r--lib/pure/parsecfg.nim94
-rw-r--r--lib/pure/parseutils.nim183
-rw-r--r--lib/pure/random.nim22
-rw-r--r--lib/pure/streams.nim913
-rw-r--r--lib/pure/strformat.nim23
-rw-r--r--lib/pure/times.nim15
-rw-r--r--lib/pure/unittest.nim10
-rw-r--r--lib/system.nim46
-rw-r--r--lib/system/ansi_c.nim2
-rw-r--r--lib/system/fatal.nim2
-rw-r--r--lib/system/strmantle.nim40
-rw-r--r--lib/system/threads.nim5
39 files changed, 1880 insertions, 794 deletions
diff --git a/lib/core/macros.nim b/lib/core/macros.nim
index 7a8755299..6a4c094d0 100644
--- a/lib/core/macros.nim
+++ b/lib/core/macros.nim
@@ -1076,20 +1076,24 @@ proc expectKind*(n: NimNode; k: set[NimNodeKind]) {.compileTime.} =
   ## macros that check the AST that is passed to them.
   if n.kind notin k: error("Expected one of " & $k & ", got " & $n.kind, n)
 
-proc newProc*(name = newEmptyNode(); params: openArray[NimNode] = [newEmptyNode()];
-    body: NimNode = newStmtList(), procType = nnkProcDef): NimNode {.compileTime.} =
+proc newProc*(name = newEmptyNode();
+              params: openArray[NimNode] = [newEmptyNode()];
+              body: NimNode = newStmtList();
+              procType = nnkProcDef;
+              pragmas: NimNode = newEmptyNode()): NimNode {.compileTime.} =
   ## shortcut for creating a new proc
   ##
   ## The ``params`` array must start with the return type of the proc,
   ## followed by a list of IdentDefs which specify the params.
   if procType notin RoutineNodes:
     error("Expected one of " & $RoutineNodes & ", got " & $procType)
+  pragmas.expectKind({nnkEmpty, nnkPragma})
   result = newNimNode(procType).add(
     name,
     newEmptyNode(),
     newEmptyNode(),
     newNimNode(nnkFormalParams).add(params),
-    newEmptyNode(),  # pragmas
+    pragmas,
     newEmptyNode(),
     body)
 
diff --git a/lib/core/runtime_v2.nim b/lib/core/runtime_v2.nim
index f76fd2f3e..0165833b4 100644
--- a/lib/core/runtime_v2.nim
+++ b/lib/core/runtime_v2.nim
@@ -47,8 +47,9 @@ proc nimNewObj(size: int): pointer {.compilerRtl.} =
   when defined(nimscript):
     discard
   elif defined(useMalloc):
-    result = c_malloc(s) +! sizeof(RefHeader)
-    nimZeroMem(result, s)
+    var orig = c_malloc(s)
+    nimZeroMem(orig, s)
+    result = orig +! sizeof(RefHeader)
   else:
     result = alloc0(s) +! sizeof(RefHeader)
   inc allocs
diff --git a/lib/core/seqs.nim b/lib/core/seqs.nim
index a79f0c2f5..9c88040ba 100644
--- a/lib/core/seqs.nim
+++ b/lib/core/seqs.nim
@@ -104,6 +104,10 @@ proc newSeqPayload(cap, elemSize: int): pointer {.compilerRtl, raises: [].} =
 proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.
     compilerRtl, noSideEffect, raises: [].} =
   {.noSideEffect.}:
+    template `+!`(p: pointer, s: int): pointer =
+      cast[pointer](cast[int](p) +% s)
+
+    const headerSize = sizeof(int) + sizeof(Allocator)
     if addlen <= 0:
       result = p
     elif p == nil:
@@ -112,14 +116,23 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize: int): pointer {.
       # Note: this means we cannot support things that have internal pointers as
       # they get reallocated here. This needs to be documented clearly.
       var p = cast[ptr PayloadBase](p)
-      let allocator = if p.allocator == nil: getLocalAllocator() else: p.allocator
       let cap = max(resize(p.cap), len+addlen)
-      var q = cast[ptr PayloadBase](allocator.realloc(allocator, p,
-        sizeof(int) + sizeof(Allocator) + elemSize * p.cap,
-        sizeof(int) + sizeof(Allocator) + elemSize * cap))
-      q.allocator = allocator
-      q.cap = cap
-      result = q
+      if p.allocator == nil:
+        let allocator = getLocalAllocator()
+        var q = cast[ptr PayloadBase](allocator.alloc(allocator,
+          headerSize + elemSize * cap))
+        copyMem(q +! headerSize, p +! headerSize, len * elemSize)
+        q.allocator = allocator
+        q.cap = cap
+        result = q
+      else:
+        let allocator = p.allocator
+        var q = cast[ptr PayloadBase](allocator.realloc(allocator, p,
+          headerSize + elemSize * p.cap,
+          headerSize + elemSize * cap))
+        q.allocator = allocator
+        q.cap = cap
+        result = q
 
 proc shrink*[T](x: var seq[T]; newLen: Natural) =
   mixin `=destroy`
@@ -140,6 +153,20 @@ proc grow*[T](x: var seq[T]; newLen: Natural; value: T) =
   for i in oldLen .. newLen-1:
     xu.p.data[i] = value
 
+proc add*[T](x: var seq[T]; value: sink T) {.magic: "AppendSeqElem", noSideEffect.} =
+  ## Generic proc for adding a data item `y` to a container `x`.
+  ##
+  ## For containers that have an order, `add` means *append*. New generic
+  ## containers should also call their adding proc `add` for consistency.
+  ## Generic code becomes much easier to write if the Nim naming scheme is
+  ## respected.
+  let oldLen = x.len
+  var xu = cast[ptr NimSeqV2[T]](addr x)
+  if xu.p == nil or xu.p.cap < oldLen+1:
+    xu.p = cast[typeof(xu.p)](prepareSeqAdd(oldLen, xu.p, 1, sizeof(T)))
+  xu.len = oldLen+1
+  xu.p.data[oldLen] = value
+
 proc setLen[T](s: var seq[T], newlen: Natural) =
   {.noSideEffect.}:
     if newlen < s.len:
diff --git a/lib/impure/db_mysql.nim b/lib/impure/db_mysql.nim
index 2fcb56202..9c24de33a 100644
--- a/lib/impure/db_mysql.nim
+++ b/lib/impure/db_mysql.nim
@@ -14,7 +14,7 @@
 ## `db_postgres <db_postgres.html>`_.
 ##
 ## Parameter substitution
-## ----------------------
+## ======================
 ##
 ## All ``db_*`` modules support the same form of parameter substitution.
 ## That is, using the ``?`` (question mark) to signify the place where a
@@ -25,10 +25,10 @@
 ##
 ##
 ## Examples
-## --------
+## ========
 ##
 ## Opening a connection to a database
-## ==================================
+## ----------------------------------
 ##
 ## .. code-block:: Nim
 ##     import db_mysql
@@ -36,7 +36,7 @@
 ##     db.close()
 ##
 ## Creating a table
-## ================
+## ----------------
 ##
 ## .. code-block:: Nim
 ##      db.exec(sql"DROP TABLE IF EXISTS myTable")
@@ -45,14 +45,14 @@
 ##                       name varchar(50) not null)"""))
 ##
 ## Inserting data
-## ==============
+## --------------
 ##
 ## .. code-block:: Nim
 ##     db.exec(sql"INSERT INTO myTable (id, name) VALUES (0, ?)",
 ##             "Dominik")
 ##
 ## Larger example
-## ==============
+## --------------
 ##
 ## .. code-block:: Nim
 ##
diff --git a/lib/impure/db_odbc.nim b/lib/impure/db_odbc.nim
index b621d652d..4c33a5a82 100644
--- a/lib/impure/db_odbc.nim
+++ b/lib/impure/db_odbc.nim
@@ -20,7 +20,7 @@
 ## `db_mysql <db_mysql.html>`_.
 ##
 ## Parameter substitution
-## ----------------------
+## ======================
 ##
 ## All ``db_*`` modules support the same form of parameter substitution.
 ## That is, using the ``?`` (question mark) to signify the place where a
@@ -31,10 +31,10 @@
 ##
 ##
 ## Examples
-## --------
+## ========
 ##
 ## Opening a connection to a database
-## ==================================
+## ----------------------------------
 ##
 ## .. code-block:: Nim
 ##     import db_odbc
@@ -42,7 +42,7 @@
 ##     db.close()
 ##
 ## Creating a table
-## ================
+## ----------------
 ##
 ## .. code-block:: Nim
 ##      db.exec(sql"DROP TABLE IF EXISTS myTable")
@@ -51,14 +51,14 @@
 ##                       name varchar(50) not null)"""))
 ##
 ## Inserting data
-## ==============
+## --------------
 ##
 ## .. code-block:: Nim
 ##     db.exec(sql"INSERT INTO myTable (id, name) VALUES (0, ?)",
 ##             "Andreas")
 ##
 ## Large example
-## =============
+## -------------
 ##
 ## .. code-block:: Nim
 ##
diff --git a/lib/impure/db_postgres.nim b/lib/impure/db_postgres.nim
index 800673ca0..ec804072f 100644
--- a/lib/impure/db_postgres.nim
+++ b/lib/impure/db_postgres.nim
@@ -14,7 +14,7 @@
 ## `db_mysql <db_mysql.html>`_.
 ##
 ## Parameter substitution
-## ----------------------
+## ======================
 ##
 ## All ``db_*`` modules support the same form of parameter substitution.
 ## That is, using the ``?`` (question mark) to signify the place where a
@@ -38,10 +38,10 @@
 ##           3)
 ##
 ## Examples
-## --------
+## ========
 ##
 ## Opening a connection to a database
-## ==================================
+## ----------------------------------
 ##
 ## .. code-block:: Nim
 ##     import db_postgres
@@ -49,7 +49,7 @@
 ##     db.close()
 ##
 ## Creating a table
-## ================
+## ----------------
 ##
 ## .. code-block:: Nim
 ##      db.exec(sql"DROP TABLE IF EXISTS myTable")
@@ -58,7 +58,7 @@
 ##                       name varchar(50) not null)"""))
 ##
 ## Inserting data
-## ==============
+## --------------
 ##
 ## .. code-block:: Nim
 ##     db.exec(sql"INSERT INTO myTable (id, name) VALUES (0, ?)",
diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim
index 3910992bb..ad2be5882 100644
--- a/lib/impure/db_sqlite.nim
+++ b/lib/impure/db_sqlite.nim
@@ -14,7 +14,7 @@
 ## `db_mysql <db_mysql.html>`_.
 ##
 ## Parameter substitution
-## ----------------------
+## ======================
 ##
 ## All ``db_*`` modules support the same form of parameter substitution.
 ## That is, using the ``?`` (question mark) to signify the place where a
@@ -24,10 +24,10 @@
 ##     sql"INSERT INTO myTable (colA, colB, colC) VALUES (?, ?, ?)"
 ##
 ## Examples
-## --------
+## ========
 ##
 ## Opening a connection to a database
-## ==================================
+## ----------------------------------
 ##
 ## .. code-block:: Nim
 ##     import db_sqlite
@@ -35,7 +35,7 @@
 ##     db.close()
 ##
 ## Creating a table
-## ================
+## ----------------
 ##
 ## .. code-block:: Nim
 ##      db.exec(sql"DROP TABLE IF EXISTS myTable")
@@ -44,14 +44,14 @@
 ##                       name varchar(50) not null)"""))
 ##
 ## Inserting data
-## ==============
+## --------------
 ##
 ## .. code-block:: Nim
 ##     db.exec(sql"INSERT INTO myTable (id, name) VALUES (0, ?)",
 ##             "Jack")
 ##
 ## Larger example
-## ==============
+## --------------
 ##
 ## .. code-block:: nim
 ##
diff --git a/lib/impure/nre.nim b/lib/impure/nre.nim
index 5c5125ba1..7014af42a 100644
--- a/lib/impure/nre.nim
+++ b/lib/impure/nre.nim
@@ -6,18 +6,6 @@
 #    distribution, for details about the copyright.
 #
 
-
-from pcre import nil
-import nre/private/util
-import tables
-from strutils import `%`
-from math import ceil
-import options
-from unicode import runeLenAt
-
-export options
-
-
 ## What is NRE?
 ## ============
 ##
@@ -67,6 +55,15 @@ runnableExamples:
     let matchBounds = firstVowel.get().captureBounds[-1]
     doAssert matchBounds.a == 1
 
+from pcre import nil
+import nre/private/util
+import tables
+from strutils import `%`
+from math import ceil
+import options
+from unicode import runeLenAt
+
+export options
 
 # Type definitions {{{
 type
diff --git a/lib/js/asyncjs.nim b/lib/js/asyncjs.nim
index 7439b66e1..219b1bed5 100644
--- a/lib/js/asyncjs.nim
+++ b/lib/js/asyncjs.nim
@@ -50,7 +50,7 @@
 ##   proc loadGame(name: string): Future[Game] {.async.}
 ##
 ## JavaScript compatibility
-## ~~~~~~~~~~~~~~~~~~~~~~~~~
+## ========================
 ##
 ## Nim currently generates `async/await` JavaScript code which is supported in modern
 ## EcmaScript and most modern versions of browsers, Node.js and Electron.
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index 08fa60dbc..2fb00d6a7 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -7,23 +7,6 @@
 #    distribution, for details about the copyright.
 #
 
-include "system/inclrtl"
-
-import os, tables, strutils, times, heapqueue, lists, options, asyncstreams
-import options, math
-import asyncfutures except callSoon
-
-import nativesockets, net, deques
-
-export Port, SocketFlag
-export asyncfutures except callSoon
-export asyncstreams
-
-#{.injectStmt: newGcInvariant().}
-
-## AsyncDispatch
-## *************
-##
 ## This module implements asynchronous IO. This includes a dispatcher,
 ## a ``Future`` type implementation, and an ``async`` macro which allows
 ## asynchronous code to be written in a synchronous style with the ``await``
@@ -82,7 +65,7 @@ export asyncstreams
 ## error), if there is no error however it returns the value of the future.
 ##
 ## Asynchronous procedures
-## -----------------------
+## =======================
 ##
 ## Asynchronous procedures remove the pain of working with callbacks. They do
 ## this by allowing you to write asynchronous code the same way as you would
@@ -116,7 +99,7 @@ export asyncstreams
 ## exceptions in async procs.
 ##
 ## Handling Exceptions
-## ~~~~~~~~~~~~~~~~~~~
+## -------------------
 ##
 ## The most reliable way to handle exceptions is to use ``yield`` on a future
 ## then check the future's ``failed`` property. For example:
@@ -142,7 +125,7 @@ export asyncstreams
 ##
 ##
 ## Discarding futures
-## ------------------
+## ==================
 ##
 ## Futures should **never** be discarded. This is because they may contain
 ## errors. If you do not care for the result of a Future then you should
@@ -151,17 +134,31 @@ export asyncstreams
 ## ``waitFor`` for that purpose.
 ##
 ## Examples
-## --------
+## ========
 ##
 ## For examples take a look at the documentation for the modules implementing
 ## asynchronous IO. A good place to start is the
 ## `asyncnet module <asyncnet.html>`_.
 ##
 ## Limitations/Bugs
-## ----------------
+## ================
 ##
 ## * The effect system (``raises: []``) does not work with async procedures.
 
+include "system/inclrtl"
+
+import os, tables, strutils, times, heapqueue, lists, options, asyncstreams
+import options, math
+import asyncfutures except callSoon
+
+import nativesockets, net, deques
+
+export Port, SocketFlag
+export asyncfutures except callSoon
+export asyncstreams
+
+#{.injectStmt: newGcInvariant().}
+
 # TODO: Check if yielded future is nil and throw a more meaningful exception
 
 type
@@ -1827,4 +1824,4 @@ proc setEvent*(ev: AsyncEvent) {.deprecated.} =
   ## Set event ``ev`` to signaled state.
   ##
   ## **Deprecated since v0.18.0:** Use ``trigger`` instead.
-  ev.trigger()
\ No newline at end of file
+  ev.trigger()
diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim
index d28e9fb57..3e741c304 100644
--- a/lib/pure/asyncftpclient.nim
+++ b/lib/pure/asyncftpclient.nim
@@ -16,7 +16,7 @@
 ## * Navigation through the FTP server's directories.
 ##
 ## Connecting to an FTP server
-## ------------------------
+## ===========================
 ##
 ## In order to begin any sort of transfer of files you must first
 ## connect to an FTP server. You can do so with the ``connect`` procedure.
@@ -34,7 +34,7 @@
 ## client will be connected after the ``await ftp.connect()`` call.
 ##
 ## Uploading a new file
-## --------------------
+## ====================
 ##
 ## After a connection is made you can use the ``store`` procedure to upload
 ## a new file to the FTP server. Make sure to check you are in the correct
@@ -53,7 +53,7 @@
 ##      waitFor(main())
 ##
 ## Checking the progress of a file transfer
-## ----------------------------------------
+## ========================================
 ##
 ## The progress of either a file upload or a file download can be checked
 ## by specifying a ``onProgressChanged`` procedure to the ``store`` or
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
index 4aed42683..4045609a4 100644
--- a/lib/pure/asynchttpserver.nim
+++ b/lib/pure/asynchttpserver.nim
@@ -14,9 +14,8 @@
 ## application you should use a reverse proxy (for example nginx) instead of
 ## allowing users to connect directly to this server.
 ##
-##
 ## Basic usage
-## -----------
+## ===========
 ##
 ## This example will create an HTTP server on port 8080. The server will
 ## respond to all requests with a ``200 OK`` response code and "Hello World"
diff --git a/lib/pure/asyncmacro.nim b/lib/pure/asyncmacro.nim
index 23ddf4777..d2750f728 100644
--- a/lib/pure/asyncmacro.nim
+++ b/lib/pure/asyncmacro.nim
@@ -7,8 +7,6 @@
 #    distribution, for details about the copyright.
 #
 
-## AsyncMacro
-## *************
 ## `asyncdispatch` module depends on the `asyncmacro` module to work properly.
 
 import macros, strutils, asyncfutures
diff --git a/lib/pure/asyncnet.nim b/lib/pure/asyncnet.nim
index 94429a657..d7cb5a18a 100644
--- a/lib/pure/asyncnet.nim
+++ b/lib/pure/asyncnet.nim
@@ -11,7 +11,7 @@
 ## asynchronous dispatcher defined in the ``asyncdispatch`` module.
 ##
 ## Asynchronous IO in Nim
-## ----------------------
+## ======================
 ##
 ## Async IO in Nim consists of multiple layers (from highest to lowest):
 ##
@@ -49,7 +49,7 @@
 ## over all the layers, providing some extra features such as buffering.
 ##
 ## SSL
-## ----
+## ===
 ##
 ## SSL can be enabled by compiling with the ``-d:ssl`` flag.
 ##
@@ -58,10 +58,10 @@
 ## the newly created SSL context to get an SSL socket.
 ##
 ## Examples
-## --------
+## ========
 ##
 ## Chat server
-## ^^^^^^^^^^^
+## -----------
 ##
 ## The following example demonstrates a simple chat server.
 ##
diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim
index 427f93926..5985592ff 100644
--- a/lib/pure/base64.nim
+++ b/lib/pure/base64.nim
@@ -15,7 +15,6 @@
 ## bytes (i.e., a total of 24 bits) can therefore be represented by
 ## four 6-bit Base64 digits.
 ##
-##
 ## Basic usage
 ## ===========
 ##
diff --git a/lib/pure/collections/hashcommon.nim b/lib/pure/collections/hashcommon.nim
new file mode 100644
index 000000000..bbc6d401d
--- /dev/null
+++ b/lib/pure/collections/hashcommon.nim
@@ -0,0 +1,68 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2019 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# An ``include`` file which contains common code for
+# hash sets and tables.
+
+const
+  growthFactor = 2
+
+when not defined(nimHasDefault):
+  template default[T](t: typedesc[T]): T =
+    var v: T
+    v
+
+# hcode for real keys cannot be zero.  hcode==0 signifies an empty slot.  These
+# two procs retain clarity of that encoding without the space cost of an enum.
+proc isEmpty(hcode: Hash): bool {.inline.} =
+  result = hcode == 0
+
+proc isFilled(hcode: Hash): bool {.inline.} =
+  result = hcode != 0
+
+proc nextTry(h, maxHash: Hash): Hash {.inline.} =
+  result = (h + 1) and maxHash
+
+proc mustRehash(length, counter: int): bool {.inline.} =
+  assert(length > counter)
+  result = (length * 2 < counter * 3) or (length - counter < 4)
+
+template rawGetKnownHCImpl() {.dirty.} =
+  if t.dataLen == 0:
+    return -1
+  var h: Hash = hc and maxHash(t)   # start with real hash value
+  while isFilled(t.data[h].hcode):
+    # Compare hc THEN key with boolean short circuit. This makes the common case
+    # zero ==key's for missing (e.g.inserts) and exactly one ==key for present.
+    # It does slow down succeeding lookups by one extra Hash cmp&and..usually
+    # just a few clock cycles, generally worth it for any non-integer-like A.
+    if t.data[h].hcode == hc and t.data[h].key == key:
+      return h
+    h = nextTry(h, maxHash(t))
+  result = -1 - h                   # < 0 => MISSING; insert idx = -1 - result
+
+proc rawGetKnownHC[X, A](t: X, key: A, hc: Hash): int {.inline.} =
+  rawGetKnownHCImpl()
+
+template genHashImpl(key, hc: typed) =
+  hc = hash(key)
+  if hc == 0:       # This almost never taken branch should be very predictable.
+    hc = 314159265  # Value doesn't matter; Any non-zero favorite is fine.
+
+template genHash(key: typed): Hash =
+  var res: Hash
+  genHashImpl(key, res)
+  res
+
+template rawGetImpl() {.dirty.} =
+  genHashImpl(key, hc)
+  rawGetKnownHCImpl()
+
+proc rawGet[X, A](t: X, key: A, hc: var Hash): int {.inline.} =
+  rawGetImpl()
diff --git a/lib/pure/collections/lists.nim b/lib/pure/collections/lists.nim
index 1fd32c9fa..2278be218 100644
--- a/lib/pure/collections/lists.nim
+++ b/lib/pure/collections/lists.nim
@@ -80,14 +80,15 @@ type
   DoublyLinkedNodeObj*[T] = object ## A node a doubly linked list consists of.
     ##
     ## It consists of a `value` field, and pointers to `next` and `prev`.
-    next*, prev*: ref DoublyLinkedNodeObj[T]
+    next*: <//>(ref DoublyLinkedNodeObj[T])
+    prev*: ref DoublyLinkedNodeObj[T]
     value*: T
   DoublyLinkedNode*[T] = ref DoublyLinkedNodeObj[T]
 
   SinglyLinkedNodeObj*[T] = object ## A node a singly linked list consists of.
     ##
     ## It consists of a `value` field, and a pointer to `next`.
-    next*: ref SinglyLinkedNodeObj[T]
+    next*: <//>(ref SinglyLinkedNodeObj[T])
     value*: T
   SinglyLinkedNode*[T] = ref SinglyLinkedNodeObj[T]
 
@@ -95,19 +96,22 @@ type
     ##
     ## Use `initSinglyLinkedList proc <#initSinglyLinkedList>`_ to create
     ## a new empty list.
-    head*, tail*: SinglyLinkedNode[T]
+    head*: <//>(SinglyLinkedNode[T])
+    tail*: SinglyLinkedNode[T]
 
   DoublyLinkedList*[T] = object ## A doubly linked list.
     ##
     ## Use `initDoublyLinkedList proc <#initDoublyLinkedList>`_ to create
     ## a new empty list.
-    head*, tail*: DoublyLinkedNode[T]
+    head*: <//>(DoublyLinkedNode[T])
+    tail*: DoublyLinkedNode[T]
 
   SinglyLinkedRing*[T] = object ## A singly linked ring.
     ##
     ## Use `initSinglyLinkedRing proc <#initSinglyLinkedRing>`_ to create
     ## a new empty ring.
-    head*, tail*: SinglyLinkedNode[T]
+    head*: <//>(SinglyLinkedNode[T])
+    tail*: SinglyLinkedNode[T]
 
   DoublyLinkedRing*[T] = object ## A doubly linked ring.
     ##
@@ -147,7 +151,7 @@ proc initDoublyLinkedRing*[T](): DoublyLinkedRing[T] =
     var a = initDoublyLinkedRing[int]()
   discard
 
-proc newDoublyLinkedNode*[T](value: T): DoublyLinkedNode[T] =
+proc newDoublyLinkedNode*[T](value: T): <//>(DoublyLinkedNode[T]) =
   ## Creates a new doubly linked node with the given `value`.
   runnableExamples:
     var n = newDoublyLinkedNode[int](5)
@@ -156,7 +160,7 @@ proc newDoublyLinkedNode*[T](value: T): DoublyLinkedNode[T] =
   new(result)
   result.value = value
 
-proc newSinglyLinkedNode*[T](value: T): SinglyLinkedNode[T] =
+proc newSinglyLinkedNode*[T](value: T): <//>(SinglyLinkedNode[T]) =
   ## Creates a new singly linked node with the given `value`.
   runnableExamples:
     var n = newSinglyLinkedNode[int](5)
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index 253340379..e39c1fb80 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -949,6 +949,14 @@ macro mapLiterals*(constructor, op: untyped;
   ## works for nested tuples of arrays of sets etc.
   result = mapLitsImpl(constructor, op, nested.boolVal)
 
+iterator items*[T](xs: iterator: T): T =
+  ## iterates over each element yielded by a closure iterator. This may
+  ## not seem particularly useful on its own, but this allows closure
+  ## iterators to be used by the the mapIt, filterIt, allIt, anyIt, etc.
+  ## templates.
+  for x in xs():
+    yield x
+
 when isMainModule:
   import strutils
   from algorithm import sorted
@@ -1382,5 +1390,13 @@ when isMainModule:
     doAssert outp == @[@["a", "b"], @["c", "d"]]
 
 
+  block:
+    proc iter(len: int): auto =
+      result = iterator(): int =
+        for i in 0..<len:
+          yield i
+
+    doAssert: iter(3).mapIt(2*it).foldl(a + b) == 6
+
   when not defined(testing):
     echo "Finished doc tests"
diff --git a/lib/pure/collections/setimpl.nim b/lib/pure/collections/setimpl.nim
new file mode 100644
index 000000000..eb131b540
--- /dev/null
+++ b/lib/pure/collections/setimpl.nim
@@ -0,0 +1,153 @@
+#
+#
+#            Nim's Runtime Library
+#        (c) Copyright 2019 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# An ``include`` file for the different hash set implementations.
+
+
+template maxHash(t): untyped = high(t.data)
+template dataLen(t): untyped = len(t.data)
+
+include hashcommon
+
+template initImpl(s: typed, size: int) =
+  assert isPowerOfTwo(size)
+  when s is OrderedSet:
+    s.first = -1
+    s.last = -1
+  s.counter = 0
+  newSeq(s.data, size)
+
+template rawInsertImpl() {.dirty.} =
+  if data.len == 0:
+    initImpl(s, defaultInitialSize)
+  data[h].key = key
+  data[h].hcode = hc
+
+proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A,
+                  hc: Hash, h: Hash) =
+  rawInsertImpl()
+
+proc enlarge[A](s: var HashSet[A]) =
+  var n: KeyValuePairSeq[A]
+  newSeq(n, len(s.data) * growthFactor)
+  swap(s.data, n)                   # n is now old seq
+  for i in countup(0, high(n)):
+    if isFilled(n[i].hcode):
+      var j = -1 - rawGetKnownHC(s, n[i].key, n[i].hcode)
+      rawInsert(s, s.data, n[i].key, n[i].hcode, j)
+
+template inclImpl() {.dirty.} =
+  if s.data.len == 0:
+    initImpl(s, defaultInitialSize)
+  var hc: Hash
+  var index = rawGet(s, key, hc)
+  if index < 0:
+    if mustRehash(len(s.data), s.counter):
+      enlarge(s)
+      index = rawGetKnownHC(s, key, hc)
+    rawInsert(s, s.data, key, hc, -1 - index)
+    inc(s.counter)
+
+template containsOrInclImpl() {.dirty.} =
+  if s.data.len == 0:
+    initImpl(s, defaultInitialSize)
+  var hc: Hash
+  var index = rawGet(s, key, hc)
+  if index >= 0:
+    result = true
+  else:
+    if mustRehash(len(s.data), s.counter):
+      enlarge(s)
+      index = rawGetKnownHC(s, key, hc)
+    rawInsert(s, s.data, key, hc, -1 - index)
+    inc(s.counter)
+
+template doWhile(a, b) =
+  while true:
+    b
+    if not a: break
+
+proc exclImpl[A](s: var HashSet[A], key: A) : bool {. inline .} =
+  var hc: Hash
+  var i = rawGet(s, key, hc)
+  var msk = high(s.data)
+  result = true
+
+  if i >= 0:
+    result = false
+    dec(s.counter)
+    while true:         # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1
+      var j = i         # The correctness of this depends on (h+1) in nextTry,
+      var r = j         # though may be adaptable to other simple sequences.
+      s.data[i].hcode = 0              # mark current EMPTY
+      s.data[i].key = default(type(s.data[i].key))
+      doWhile((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)):
+        i = (i + 1) and msk            # increment mod table size
+        if isEmpty(s.data[i].hcode):   # end of collision cluster; So all done
+          return
+        r = s.data[i].hcode and msk    # "home" location of key@i
+      shallowCopy(s.data[j], s.data[i]) # data[i] will be marked EMPTY next loop
+
+template dollarImpl() {.dirty.} =
+  result = "{"
+  for key in items(s):
+    if result.len > 1: result.add(", ")
+    result.addQuoted(key)
+  result.add("}")
+
+
+
+# --------------------------- OrderedSet ------------------------------
+
+proc rawGet[A](t: OrderedSet[A], key: A, hc: var Hash): int {.inline.} =
+  rawGetImpl()
+
+proc rawInsert[A](s: var OrderedSet[A], data: var OrderedKeyValuePairSeq[A],
+                  key: A, hc: Hash, h: Hash) =
+  rawInsertImpl()
+  data[h].next = -1
+  if s.first < 0: s.first = h
+  if s.last >= 0: data[s.last].next = h
+  s.last = h
+
+proc enlarge[A](s: var OrderedSet[A]) =
+  var n: OrderedKeyValuePairSeq[A]
+  newSeq(n, len(s.data) * growthFactor)
+  var h = s.first
+  s.first = -1
+  s.last = -1
+  swap(s.data, n)
+  while h >= 0:
+    var nxt = n[h].next
+    if isFilled(n[h].hcode):
+      var j = -1 - rawGetKnownHC(s, n[h].key, n[h].hcode)
+      rawInsert(s, s.data, n[h].key, n[h].hcode, j)
+    h = nxt
+
+proc exclImpl[A](s: var OrderedSet[A], key: A) : bool {.inline.} =
+  if len(s.data) == 0:
+    return true
+  var n: OrderedKeyValuePairSeq[A]
+  newSeq(n, len(s.data))
+  var h = s.first
+  s.first = -1
+  s.last = -1
+  swap(s.data, n)
+  let hc = genHash(key)
+  result = true
+  while h >= 0:
+    var nxt = n[h].next
+    if isFilled(n[h].hcode):
+      if n[h].hcode == hc and n[h].key == key:
+        dec s.counter
+        result = false
+      else:
+        var j = -1 - rawGetKnownHC(s, n[h].key, n[h].hcode)
+        rawInsert(s, s.data, n[h].key, n[h].hcode, j)
+    h = nxt
diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim
index 29bf31f96..86a72533e 100644
--- a/lib/pure/collections/sets.nim
+++ b/lib/pure/collections/sets.nim
@@ -26,7 +26,7 @@
 ##   `symmetric difference <#symmetricDifference,HashSet[A],HashSet[A]>`_
 ##
 ## .. code-block::
-##   echo toHashSet([9, 5, 1])         # {9, 1, 5}
+##   echo toHashSet([9, 5, 1])     # {9, 1, 5}
 ##   echo toOrderedSet([9, 5, 1])  # {9, 5, 1}
 ##
 ##   let
@@ -69,148 +69,32 @@ type
     data: KeyValuePairSeq[A]
     counter: int
 
+type
+  OrderedKeyValuePair[A] = tuple[
+    hcode: Hash, next: int, key: A]
+  OrderedKeyValuePairSeq[A] = seq[OrderedKeyValuePair[A]]
+  OrderedSet* {.myShallow.} [A] = object ## \
+    ## A generic hash set that remembers insertion order.
+    ##
+    ## Use `init proc <#init,OrderedSet[A],int>`_ or `initOrderedSet proc
+    ## <#initOrderedSet,int>`_ before calling other procs on it.
+    data: OrderedKeyValuePairSeq[A]
+    counter, first, last: int
 
-# ---------------------- helpers -----------------------------------
-
-const growthFactor = 2
-
-when not defined(nimHasDefault):
-  template default[T](t: typedesc[T]): T =
-    ## Used by clear methods to get a default value.
-    var v: T
-    v
-
-# hcode for real keys cannot be zero.  hcode==0 signifies an empty slot.  These
-# two procs retain clarity of that encoding without the space cost of an enum.
-proc isEmpty(hcode: Hash): bool {.inline.} =
-  result = hcode == 0
-
-proc isFilled(hcode: Hash): bool {.inline.} =
-  result = hcode != 0
-
-proc nextTry(h, maxHash: Hash): Hash {.inline.} =
-  result = (h + 1) and maxHash
-
-template rawGetKnownHCImpl() {.dirty.} =
-  var h: Hash = hc and high(s.data)  # start with real hash value
-  while isFilled(s.data[h].hcode):
-    # Compare hc THEN key with boolean short circuit. This makes the common case
-    # zero ==key's for missing (e.g.inserts) and exactly one ==key for present.
-    # It does slow down succeeding lookups by one extra Hash cmp&and..usually
-    # just a few clock cycles, generally worth it for any non-integer-like A.
-    if s.data[h].hcode == hc and s.data[h].key == key:  # compare hc THEN key
-      return h
-    h = nextTry(h, high(s.data))
-  result = -1 - h                   # < 0 => MISSING; insert idx = -1 - result
-
-template genHash(key: typed): Hash =
-  var hc = hash(key)
-  if hc == 0:       # This almost never taken branch should be very predictable.
-    hc = 314159265  # Value doesn't matter; Any non-zero favorite is fine.
-  hc
-
-template rawGetImpl() {.dirty.} =
-  hc = genHash(key)
-  rawGetKnownHCImpl()
-
-template rawInsertImpl() {.dirty.} =
-  data[h].key = key
-  data[h].hcode = hc
-
-proc rawGetKnownHC[A](s: HashSet[A], key: A, hc: Hash): int {.inline.} =
-  rawGetKnownHCImpl()
-
-proc rawGet[A](s: HashSet[A], key: A, hc: var Hash): int {.inline.} =
-  rawGetImpl()
-
-proc rawInsert[A](s: var HashSet[A], data: var KeyValuePairSeq[A], key: A,
-                  hc: Hash, h: Hash) =
-  rawInsertImpl()
-
-proc enlarge[A](s: var HashSet[A]) =
-  var n: KeyValuePairSeq[A]
-  newSeq(n, len(s.data) * growthFactor)
-  swap(s.data, n)                   # n is now old seq
-  for i in countup(0, high(n)):
-    if isFilled(n[i].hcode):
-      var j = -1 - rawGetKnownHC(s, n[i].key, n[i].hcode)
-      rawInsert(s, s.data, n[i].key, n[i].hcode, j)
-
-template inclImpl() {.dirty.} =
-  var hc: Hash
-  var index = rawGet(s, key, hc)
-  if index < 0:
-    if mustRehash(len(s.data), s.counter):
-      enlarge(s)
-      index = rawGetKnownHC(s, key, hc)
-    rawInsert(s, s.data, key, hc, -1 - index)
-    inc(s.counter)
-
-template containsOrInclImpl() {.dirty.} =
-  var hc: Hash
-  var index = rawGet(s, key, hc)
-  if index >= 0:
-    result = true
-  else:
-    if mustRehash(len(s.data), s.counter):
-      enlarge(s)
-      index = rawGetKnownHC(s, key, hc)
-    rawInsert(s, s.data, key, hc, -1 - index)
-    inc(s.counter)
-
-template doWhile(a, b) =
-  while true:
-    b
-    if not a: break
-
-proc exclImpl[A](s: var HashSet[A], key: A) : bool {. inline .} =
-  assert s.isValid, "The set needs to be initialized."
-  var hc: Hash
-  var i = rawGet(s, key, hc)
-  var msk = high(s.data)
-  result = true
+const
+  defaultInitialSize* = 64
 
-  if i >= 0:
-    result = false
-    dec(s.counter)
-    while true:         # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1
-      var j = i         # The correctness of this depends on (h+1) in nextTry,
-      var r = j         # though may be adaptable to other simple sequences.
-      s.data[i].hcode = 0              # mark current EMPTY
-      s.data[i].key = default(type(s.data[i].key))
-      doWhile((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)):
-        i = (i + 1) and msk            # increment mod table size
-        if isEmpty(s.data[i].hcode):   # end of collision cluster; So all done
-          return
-        r = s.data[i].hcode and msk    # "home" location of key@i
-      shallowCopy(s.data[j], s.data[i]) # data[i] will be marked EMPTY next loop
-
-proc mustRehash(length, counter: int): bool {.inline.} =
-  assert(length > counter)
-  result = (length * 2 < counter * 3) or (length - counter < 4)
-
-template dollarImpl() {.dirty.} =
-  result = "{"
-  for key in items(s):
-    if result.len > 1: result.add(", ")
-    result.addQuoted(key)
-  result.add("}")
+include setimpl
 
 proc rightSize*(count: Natural): int {.inline.}
 
 
-
-
-
-
-
-
 # ---------------------------------------------------------------------
 # ------------------------------ HashSet ------------------------------
 # ---------------------------------------------------------------------
 
 
-proc init*[A](s: var HashSet[A], initialSize=64) =
+proc init*[A](s: var HashSet[A], initialSize = defaultInitialSize) =
   ## Initializes a hash set.
   ##
   ## The `initialSize` parameter needs to be a power of two (default: 64).
@@ -218,9 +102,8 @@ proc init*[A](s: var HashSet[A], initialSize=64) =
   ## `math.nextPowerOfTwo proc <math.html#nextPowerOfTwo>`_ or `rightSize proc
   ## <#rightSize,Natural>`_ from this module.
   ##
-  ## All set variables must be initialized before
-  ## use with other procs from this module, with the exception of `isValid proc
-  ## <#isValid,HashSet[A]>`_ and `len() <#len,HashSet[A]>`_.
+  ## Starting from Nim v0.20, sets are initialized by default and it is
+  ## not necessary to call this function explicitly.
   ##
   ## You can call this proc on a previously initialized hash set, which will
   ## discard all its values. This might be more convenient than iterating over
@@ -235,42 +118,26 @@ proc init*[A](s: var HashSet[A], initialSize=64) =
     init(a)
     assert a.isValid
 
-  assert isPowerOfTwo(initialSize)
-  s.counter = 0
-  newSeq(s.data, initialSize)
+  initImpl(s, initialSize)
 
-proc initHashSet*[A](initialSize=64): HashSet[A] =
+proc initHashSet*[A](initialSize = defaultInitialSize): HashSet[A] =
   ## Wrapper around `init proc <#init,HashSet[A],int>`_ for initialization of
   ## hash sets.
   ##
   ## Returns an empty hash set you can assign directly in ``var`` blocks in a
   ## single line.
   ##
+  ## Starting from Nim v0.20, sets are initialized by default and it is
+  ## not necessary to call this function explicitly.
+  ##
   ## See also:
   ## * `toHashSet proc <#toHashSet,openArray[A]>`_
   runnableExamples:
     var a = initHashSet[int]()
-    assert a.isValid
     a.incl(3)
     assert len(a) == 1
-  result.init(initialSize)
 
-proc isValid*[A](s: HashSet[A]): bool =
-  ## Returns `true` if the set has been initialized (with `initHashSet proc
-  ## <#initHashSet,int>`_ or `init proc <#init,HashSet[A],int>`_).
-  ##
-  ## Most operations over an uninitialized set will crash at runtime and
-  ## `assert <system.html#assert>`_ in debug builds. You can use this proc in
-  ## your own procs to verify that sets passed to your procs are correctly
-  ## initialized.
-  ##
-  ## **Examples:**
-  ##
-  ## .. code-block ::
-  ##   proc savePreferences(options: HashSet[string]) =
-  ##     assert options.isValid, "Pass an initialized set!"
-  ##     # Do stuff here, may crash in release builds!
-  result = s.data.len > 0
+  result.init(initialSize)
 
 proc `[]`*[A](s: var HashSet[A], key: A): var A =
   ## Returns the element that is actually stored in `s` which has the same
@@ -278,7 +145,6 @@ proc `[]`*[A](s: var HashSet[A], key: A): var A =
   ##
   ## This is useful when one overloaded `hash` and `==` but still needs
   ## reference semantics for sharing.
-  assert s.isValid, "The set needs to be initialized."
   var hc: Hash
   var index = rawGet(s, key, hc)
   if index >= 0: result = s.data[index].key
@@ -305,7 +171,6 @@ proc contains*[A](s: HashSet[A], key: A): bool =
     assert values.contains(2)
     assert 2 in values
 
-  assert s.isValid, "The set needs to be initialized."
   var hc: Hash
   var index = rawGet(s, key, hc)
   result = index >= 0
@@ -325,7 +190,6 @@ proc incl*[A](s: var HashSet[A], key: A) =
     values.incl(2)
     assert values.len == 1
 
-  assert s.isValid, "The set needs to be initialized."
   inclImpl()
 
 proc incl*[A](s: var HashSet[A], other: HashSet[A]) =
@@ -344,8 +208,6 @@ proc incl*[A](s: var HashSet[A], other: HashSet[A]) =
     values.incl(others)
     assert values.len == 5
 
-  assert s.isValid, "The set `s` needs to be initialized."
-  assert other.isValid, "The set `other` needs to be initialized."
   for item in other: incl(s, item)
 
 proc toHashSet*[A](keys: openArray[A]): HashSet[A] =
@@ -368,14 +230,6 @@ proc toHashSet*[A](keys: openArray[A]): HashSet[A] =
   result = initHashSet[A](rightSize(keys.len))
   for key in items(keys): result.incl(key)
 
-proc initSet*[A](initialSize=64): HashSet[A] {.deprecated:
-     "Deprecated since v0.20, use `initHashSet`"} = initHashSet[A](initialSize)
-  ## Deprecated since v0.20, use `initHashSet`.
-
-proc toSet*[A](keys: openArray[A]): HashSet[A] {.deprecated:
-     "Deprecated since v0.20, use `toHashSet`"} = toHashSet[A](keys)
-  ## Deprecated since v0.20, use `toHashSet`.
-
 iterator items*[A](s: HashSet[A]): A =
   ## Iterates over elements of the set `s`.
   ##
@@ -395,8 +249,7 @@ iterator items*[A](s: HashSet[A]): A =
   ##   assert a.len == 2
   ##   echo b
   ##   # --> {(a: 1, b: 3), (a: 0, b: 4)}
-  assert s.isValid, "The set needs to be initialized."
-  for h in 0..high(s.data):
+  for h in 0 .. high(s.data):
     if isFilled(s.data[h].hcode): yield s.data[h].key
 
 proc containsOrIncl*[A](s: var HashSet[A], key: A): bool =
@@ -417,7 +270,6 @@ proc containsOrIncl*[A](s: var HashSet[A], key: A): bool =
     assert values.containsOrIncl(2) == true
     assert values.containsOrIncl(3) == false
 
-  assert s.isValid, "The set needs to be initialized."
   containsOrInclImpl()
 
 proc excl*[A](s: var HashSet[A], key: A) =
@@ -434,6 +286,7 @@ proc excl*[A](s: var HashSet[A], key: A) =
     s.excl(2)
     s.excl(2)
     assert s.len == 3
+
   discard exclImpl(s, key)
 
 proc excl*[A](s: var HashSet[A], other: HashSet[A]) =
@@ -453,8 +306,6 @@ proc excl*[A](s: var HashSet[A], other: HashSet[A]) =
     assert len(numbers) == 3
     ## numbers == {1, 3, 5}
 
-  assert s.isValid, "The set `s` needs to be initialized."
-  assert other.isValid, "The set `other` needs to be initialized."
   for item in other: discard exclImpl(s, item)
 
 proc missingOrExcl*[A](s: var HashSet[A], key: A): bool =
@@ -474,6 +325,7 @@ proc missingOrExcl*[A](s: var HashSet[A], key: A): bool =
     assert s.missingOrExcl(4) == true
     assert s.missingOrExcl(6) == false
     assert s.missingOrExcl(6) == true
+
   exclImpl(s, key)
 
 proc pop*[A](s: var HashSet[A]): A =
@@ -489,7 +341,7 @@ proc pop*[A](s: var HashSet[A]): A =
     assert s.pop == 2
     doAssertRaises(KeyError, echo s.pop)
 
-  for h in 0..high(s.data):
+  for h in 0 .. high(s.data):
     if isFilled(s.data[h].hcode):
       result = s.data[h].key
       excl(s, result)
@@ -510,7 +362,7 @@ proc clear*[A](s: var HashSet[A]) =
     assert len(s) == 0
 
   s.counter = 0
-  for i in 0..<s.data.len:
+  for i in 0 ..< s.data.len:
     s.data[i].hcode = 0
     s.data[i].key = default(type(s.data[i].key))
 
@@ -525,6 +377,7 @@ proc len*[A](s: HashSet[A]): int =
     assert len(a) == 0
     let s = toHashSet([3, 5, 7])
     assert len(s) == 3
+
   result = s.counter
 
 proc card*[A](s: HashSet[A]): int =
@@ -554,8 +407,6 @@ proc union*[A](s1, s2: HashSet[A]): HashSet[A] =
       c = union(a, b)
     assert c == toHashSet(["a", "b", "c"])
 
-  assert s1.isValid, "The set `s1` needs to be initialized."
-  assert s2.isValid, "The set `s2` needs to be initialized."
   result = s1
   incl(result, s2)
 
@@ -579,9 +430,7 @@ proc intersection*[A](s1, s2: HashSet[A]): HashSet[A] =
       c = intersection(a, b)
     assert c == toHashSet(["b"])
 
-  assert s1.isValid, "The set `s1` needs to be initialized."
-  assert s2.isValid, "The set `s2` needs to be initialized."
-  result = initHashSet[A](min(s1.data.len, s2.data.len))
+  result = initHashSet[A](max(min(s1.data.len, s2.data.len), 2))
   for item in s1:
     if item in s2: incl(result, item)
 
@@ -604,8 +453,6 @@ proc difference*[A](s1, s2: HashSet[A]): HashSet[A] =
       c = difference(a, b)
     assert c == toHashSet(["a"])
 
-  assert s1.isValid, "The set `s1` needs to be initialized."
-  assert s2.isValid, "The set `s2` needs to be initialized."
   result = initHashSet[A]()
   for item in s1:
     if not contains(s2, item):
@@ -631,8 +478,6 @@ proc symmetricDifference*[A](s1, s2: HashSet[A]): HashSet[A] =
       c = symmetricDifference(a, b)
     assert c == toHashSet(["a", "c"])
 
-  assert s1.isValid, "The set `s1` needs to be initialized."
-  assert s2.isValid, "The set `s2` needs to be initialized."
   result = s1
   for item in s2:
     if containsOrIncl(result, item): excl(result, item)
@@ -663,8 +508,6 @@ proc disjoint*[A](s1, s2: HashSet[A]): bool =
     assert disjoint(a, b) == false
     assert disjoint(a, b - a) == true
 
-  assert s1.isValid, "The set `s1` needs to be initialized."
-  assert s2.isValid, "The set `s2` needs to be initialized."
   for item in s1:
     if item in s2: return false
   return true
@@ -681,6 +524,7 @@ proc `<`*[A](s, t: HashSet[A]): bool =
       c = intersection(a, b)
     assert c < a and c < b
     assert(not (a < a))
+
   s.counter != t.counter and s <= t
 
 proc `<=`*[A](s, t: HashSet[A]): bool =
@@ -711,6 +555,7 @@ proc `==`*[A](s, t: HashSet[A]): bool =
       a = toHashSet([1, 2])
       b = toHashSet([2, 1])
     assert a == b
+
   s.counter == t.counter and s <= t
 
 proc map*[A, B](data: HashSet[A], op: proc (x: A): B {.closure.}): HashSet[B] =
@@ -729,8 +574,7 @@ proc map*[A, B](data: HashSet[A], op: proc (x: A): B {.closure.}): HashSet[B] =
 
 proc hash*[A](s: HashSet[A]): Hash =
   ## Hashing of HashSet.
-  assert s.isValid, "The set needs to be initialized."
-  for h in 0..high(s.data):
+  for h in 0 .. high(s.data):
     result = result xor s.data[h].hcode
   result = !$result
 
@@ -747,7 +591,6 @@ proc `$`*[A](s: HashSet[A]): string =
   ##   # --> {2, 4, 5}
   ##   echo toHashSet(["no", "esc'aping", "is \" provided"])
   ##   # --> {no, esc'aping, is " provided}
-  assert s.isValid, "The set needs to be initialized."
   dollarImpl()
 
 proc rightSize*(count: Natural): int {.inline.} =
@@ -760,8 +603,28 @@ proc rightSize*(count: Natural): int {.inline.} =
   result = nextPowerOfTwo(count * 3 div 2  +  4)
 
 
+proc initSet*[A](initialSize = defaultInitialSize): HashSet[A] {.deprecated:
+     "Deprecated since v0.20, use `initHashSet`"} = initHashSet[A](initialSize)
+  ## Deprecated since v0.20, use `initHashSet <#initHashSet,int>`_.
 
+proc toSet*[A](keys: openArray[A]): HashSet[A] {.deprecated:
+     "Deprecated since v0.20, use `toHashSet`"} = toHashSet[A](keys)
+  ## Deprecated since v0.20, use `toHashSet <#toHashSet,openArray[A]>`_.
 
+proc isValid*[A](s: HashSet[A]): bool {.deprecated:
+     "Deprecated since v0.20; sets are initialized by default"} =
+  ## **Deprecated since v0.20; sets are initialized by default**
+  ##
+  ## Returns `true` if the set has been initialized (with `initHashSet proc
+  ## <#initHashSet,int>`_ or `init proc <#init,HashSet[A],int>`_).
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block ::
+  ##   proc savePreferences(options: HashSet[string]) =
+  ##     assert options.isValid, "Pass an initialized set!"
+  ##     # Do stuff here, may crash in release builds!
+  result = s.data.len > 0
 
 
 
@@ -769,89 +632,19 @@ proc rightSize*(count: Natural): int {.inline.} =
 # --------------------------- OrderedSet ------------------------------
 # ---------------------------------------------------------------------
 
-type
-  OrderedKeyValuePair[A] = tuple[
-    hcode: Hash, next: int, key: A]
-  OrderedKeyValuePairSeq[A] = seq[OrderedKeyValuePair[A]]
-  OrderedSet* {.myShallow.} [A] = object ## \
-    ## A generic hash set that remembers insertion order.
-    ##
-    ## Use `init proc <#init,OrderedSet[A],int>`_ or `initOrderedSet proc
-    ## <#initOrderedSet,int>`_ before calling other procs on it.
-    data: OrderedKeyValuePairSeq[A]
-    counter, first, last: int
-
-
-# ---------------------- helpers -----------------------------------
-
 template forAllOrderedPairs(yieldStmt: untyped) {.dirty.} =
-  var h = s.first
-  var idx = 0
-  while h >= 0:
-    var nxt = s.data[h].next
-    if isFilled(s.data[h].hcode):
-      yieldStmt
-      inc(idx)
-    h = nxt
-
-proc rawGetKnownHC[A](s: OrderedSet[A], key: A, hc: Hash): int {.inline.} =
-  rawGetKnownHCImpl()
-
-proc rawGet[A](s: OrderedSet[A], key: A, hc: var Hash): int {.inline.} =
-  rawGetImpl()
-
-proc rawInsert[A](s: var OrderedSet[A], data: var OrderedKeyValuePairSeq[A],
-                  key: A, hc: Hash, h: Hash) =
-  rawInsertImpl()
-  data[h].next = -1
-  if s.first < 0: s.first = h
-  if s.last >= 0: data[s.last].next = h
-  s.last = h
-
-proc enlarge[A](s: var OrderedSet[A]) =
-  var n: OrderedKeyValuePairSeq[A]
-  newSeq(n, len(s.data) * growthFactor)
-  var h = s.first
-  s.first = -1
-  s.last = -1
-  swap(s.data, n)
-  while h >= 0:
-    var nxt = n[h].next
-    if isFilled(n[h].hcode):
-      var j = -1 - rawGetKnownHC(s, n[h].key, n[h].hcode)
-      rawInsert(s, s.data, n[h].key, n[h].hcode, j)
-    h = nxt
-
-proc isValid*[A](s: OrderedSet[A]): bool
-
-proc exclImpl[A](s: var OrderedSet[A], key: A) : bool {. inline .} =
-  assert s.isValid, "The set needs to be initialized."
-  var n: OrderedKeyValuePairSeq[A]
-  newSeq(n, len(s.data))
-  var h = s.first
-  s.first = -1
-  s.last = -1
-  swap(s.data, n)
-  let hc = genHash(key)
-  result = true
-  while h >= 0:
-    var nxt = n[h].next
-    if isFilled(n[h].hcode):
-      if n[h].hcode == hc and n[h].key == key:
-        dec s.counter
-        result = false
-      else:
-        var j = -1 - rawGetKnownHC(s, n[h].key, n[h].hcode)
-        rawInsert(s, s.data, n[h].key, n[h].hcode, j)
-    h = nxt
-
-
-
-# -----------------------------------------------------------------------
-
-
-
-proc init*[A](s: var OrderedSet[A], initialSize=64) =
+  if s.data.len > 0:
+    var h = s.first
+    var idx = 0
+    while h >= 0:
+      var nxt = s.data[h].next
+      if isFilled(s.data[h].hcode):
+        yieldStmt
+        inc(idx)
+      h = nxt
+
+
+proc init*[A](s: var OrderedSet[A], initialSize = defaultInitialSize) =
   ## Initializes an ordered hash set.
   ##
   ## The `initialSize` parameter needs to be a power of two (default: 64).
@@ -859,9 +652,8 @@ proc init*[A](s: var OrderedSet[A], initialSize=64) =
   ## `math.nextPowerOfTwo proc <math.html#nextPowerOfTwo>`_ or `rightSize proc
   ## <#rightSize,Natural>`_ from this module.
   ##
-  ## All set variables must be initialized before
-  ## use with other procs from this module, with the exception of `isValid proc
-  ## <#isValid,HashSet[A]>`_ and `len() <#len,HashSet[A]>`_.
+  ## Starting from Nim v0.20, sets are initialized by default and it is
+  ## not necessary to call this function explicitly.
   ##
   ## You can call this proc on a previously initialized hash set, which will
   ## discard all its values. This might be more convenient than iterating over
@@ -876,26 +668,25 @@ proc init*[A](s: var OrderedSet[A], initialSize=64) =
     init(a)
     assert a.isValid
 
-  assert isPowerOfTwo(initialSize)
-  s.counter = 0
-  s.first = -1
-  s.last = -1
-  newSeq(s.data, initialSize)
+  initImpl(s, initialSize)
 
-proc initOrderedSet*[A](initialSize=64): OrderedSet[A] =
+proc initOrderedSet*[A](initialSize = defaultInitialSize): OrderedSet[A] =
   ## Wrapper around `init proc <#init,OrderedSet[A],int>`_ for initialization of
   ## ordered hash sets.
   ##
   ## Returns an empty ordered hash set you can assign directly in ``var`` blocks
   ## in a single line.
   ##
+  ## Starting from Nim v0.20, sets are initialized by default and it is
+  ## not necessary to call this function explicitly.
+  ##
   ## See also:
   ## * `toOrderedSet proc <#toOrderedSet,openArray[A]>`_
   runnableExamples:
     var a = initOrderedSet[int]()
-    assert a.isValid
     a.incl(3)
     assert len(a) == 1
+
   result.init(initialSize)
 
 proc toOrderedSet*[A](keys: openArray[A]): OrderedSet[A] =
@@ -918,23 +709,6 @@ proc toOrderedSet*[A](keys: openArray[A]): OrderedSet[A] =
   result = initOrderedSet[A](rightSize(keys.len))
   for key in items(keys): result.incl(key)
 
-proc isValid*[A](s: OrderedSet[A]): bool =
-  ## Returns `true` if the set has been initialized (with `initHashSet proc
-  ## <#initOrderedSet,int>`_ or `init proc <#init,OrderedSet[A],int>`_).
-  ##
-  ## Most operations over an uninitialized set will crash at runtime and
-  ## `assert <system.html#assert>`_ in debug builds. You can use this proc in
-  ## your own procs to verify that sets passed to your procs are correctly
-  ## initialized.
-  ##
-  ## **Examples:**
-  ##
-  ## .. code-block ::
-  ##   proc savePreferences(options: OrderedSet[string]) =
-  ##     assert options.isValid, "Pass an initialized set!"
-  ##     # Do stuff here, may crash in release builds!
-  result = s.data.len > 0
-
 proc contains*[A](s: OrderedSet[A], key: A): bool =
   ## Returns true if `key` is in `s`.
   ##
@@ -952,7 +726,6 @@ proc contains*[A](s: OrderedSet[A], key: A): bool =
     assert values.contains(2)
     assert 2 in values
 
-  assert s.isValid, "The set needs to be initialized."
   var hc: Hash
   var index = rawGet(s, key, hc)
   result = index >= 0
@@ -972,7 +745,6 @@ proc incl*[A](s: var OrderedSet[A], key: A) =
     values.incl(2)
     assert values.len == 1
 
-  assert s.isValid, "The set needs to be initialized."
   inclImpl()
 
 proc incl*[A](s: var HashSet[A], other: OrderedSet[A]) =
@@ -988,8 +760,7 @@ proc incl*[A](s: var HashSet[A], other: OrderedSet[A]) =
       others = toOrderedSet([3, 4, 5])
     values.incl(others)
     assert values.len == 5
-  assert s.isValid, "The set `s` needs to be initialized."
-  assert other.isValid, "The set `other` needs to be initialized."
+
   for item in items(other): incl(s, item)
 
 proc containsOrIncl*[A](s: var OrderedSet[A], key: A): bool =
@@ -1009,7 +780,6 @@ proc containsOrIncl*[A](s: var OrderedSet[A], key: A): bool =
     assert values.containsOrIncl(2) == true
     assert values.containsOrIncl(3) == false
 
-  assert s.isValid, "The set needs to be initialized."
   containsOrInclImpl()
 
 proc excl*[A](s: var OrderedSet[A], key: A) =
@@ -1025,6 +795,7 @@ proc excl*[A](s: var OrderedSet[A], key: A) =
     s.excl(2)
     s.excl(2)
     assert s.len == 3
+
   discard exclImpl(s, key)
 
 proc missingOrExcl*[A](s: var OrderedSet[A], key: A): bool =
@@ -1044,6 +815,7 @@ proc missingOrExcl*[A](s: var OrderedSet[A], key: A): bool =
     assert s.missingOrExcl(4) == true
     assert s.missingOrExcl(6) == false
     assert s.missingOrExcl(6) == true
+
   exclImpl(s, key)
 
 proc clear*[A](s: var OrderedSet[A]) =
@@ -1059,7 +831,7 @@ proc clear*[A](s: var OrderedSet[A]) =
   s.counter = 0
   s.first = -1
   s.last = -1
-  for i in 0..<s.data.len:
+  for i in 0 ..< s.data.len:
     s.data[i].hcode = 0
     s.data[i].next = 0
     s.data[i].key = default(type(s.data[i].key))
@@ -1075,6 +847,7 @@ proc len*[A](s: OrderedSet[A]): int {.inline.} =
     assert len(a) == 0
     let s = toHashSet([3, 5, 7])
     assert len(s) == 3
+
   result = s.counter
 
 proc card*[A](s: OrderedSet[A]): int {.inline.} =
@@ -1110,7 +883,6 @@ proc `==`*[A](s, t: OrderedSet[A]): bool =
 
 proc hash*[A](s: OrderedSet[A]): Hash =
   ## Hashing of OrderedSet.
-  assert s.isValid, "The set needs to be initialized."
   forAllOrderedPairs:
     result = result !& s.data[h].hcode
   result = !$result
@@ -1129,7 +901,6 @@ proc `$`*[A](s: OrderedSet[A]): string =
   ##   # --> {2, 4, 5}
   ##   echo toOrderedSet(["no", "esc'aping", "is \" provided"])
   ##   # --> {no, esc'aping, is " provided}
-  assert s.isValid, "The set needs to be initialized."
   dollarImpl()
 
 
@@ -1152,11 +923,9 @@ iterator items*[A](s: OrderedSet[A]): A =
   ##   # --> Got 5
   ##   # --> Got 8
   ##   # --> Got 4
-  assert s.isValid, "The set needs to be initialized."
   forAllOrderedPairs:
     yield s.data[h].key
 
-
 iterator pairs*[A](s: OrderedSet[A]): tuple[a: int, b: A] =
   ## Iterates through (position, value) tuples of OrderedSet `s`.
   runnableExamples:
@@ -1166,12 +935,27 @@ iterator pairs*[A](s: OrderedSet[A]): tuple[a: int, b: A] =
       p.add(x)
     assert p == @[(0, 'a'), (1, 'b'), (2, 'r'), (3, 'c'), (4, 'd')]
 
-  assert s.isValid, "The set needs to be initialized"
   forAllOrderedPairs:
     yield (idx, s.data[h].key)
 
 
 
+proc isValid*[A](s: OrderedSet[A]): bool {.deprecated:
+     "Deprecated since v0.20; sets are initialized by default"} =
+  ## **Deprecated since v0.20; sets are initialized by default**
+  ##
+  ## Returns `true` if the set has been initialized (with `initHashSet proc
+  ## <#initOrderedSet,int>`_ or `init proc <#init,OrderedSet[A],int>`_).
+  ##
+  ## **Examples:**
+  ##
+  ## .. code-block ::
+  ##   proc savePreferences(options: OrderedSet[string]) =
+  ##     assert options.isValid, "Pass an initialized set!"
+  ##     # Do stuff here, may crash in release builds!
+  result = s.data.len > 0
+
+
 # -----------------------------------------------------------------------
 
 
@@ -1179,7 +963,7 @@ iterator pairs*[A](s: OrderedSet[A]): tuple[a: int, b: A] =
 when isMainModule and not defined(release):
   proc testModule() =
     ## Internal micro test to validate docstrings and such.
-    block isValidTest:
+    block isValidTest: # isValid is deprecated
       var options: HashSet[string]
       proc savePreferences(options: HashSet[string]) =
         assert options.isValid, "Pass an initialized set!"
@@ -1280,7 +1064,7 @@ when isMainModule and not defined(release):
       var b = a.map(proc (x: int): string = $x)
       assert b == toHashSet(["1", "2", "3"])
 
-    block isValidTest:
+    block isValidTest: # isValid is deprecated
       var cards: OrderedSet[string]
       proc saveTarotCards(cards: OrderedSet[string]) =
         assert cards.isValid, "Pass an initialized set!"
@@ -1393,6 +1177,69 @@ when isMainModule and not defined(release):
       bb.incl(y)
       assert aa == bb
 
+    block setsWithoutInit:
+      var
+        a: HashSet[int]
+        b: HashSet[int]
+        c: HashSet[int]
+        d: HashSet[int]
+        e: HashSet[int]
+
+      doAssert a.containsOrIncl(3) == false
+      doAssert a.contains(3)
+      doAssert a.len == 1
+      doAssert a.containsOrIncl(3)
+      a.incl(3)
+      doAssert a.len == 1
+      a.incl(6)
+      doAssert a.len == 2
+
+      b.incl(5)
+      doAssert b.len == 1
+      b.excl(5)
+      b.excl(c)
+      doAssert b.missingOrExcl(5)
+      doAssert b.disjoint(c)
+
+      d = b + c
+      doAssert d.len == 0
+      d = b * c
+      doAssert d.len == 0
+      d = b - c
+      doAssert d.len == 0
+      d = b -+- c
+      doAssert d.len == 0
+
+      doAssert (d < e) == false
+      doAssert d <= e
+      doAssert d == e
+
+    block setsWithoutInit:
+      var
+        a: OrderedSet[int]
+        b: OrderedSet[int]
+        c: OrderedSet[int]
+        d: HashSet[int]
+
+
+      doAssert a.containsOrIncl(3) == false
+      doAssert a.contains(3)
+      doAssert a.len == 1
+      doAssert a.containsOrIncl(3)
+      a.incl(3)
+      doAssert a.len == 1
+      a.incl(6)
+      doAssert a.len == 2
+
+      b.incl(5)
+      doAssert b.len == 1
+      doAssert b.missingOrExcl(5) == false
+      doAssert b.missingOrExcl(5)
+
+      doAssert c.missingOrExcl(9)
+      d.incl(c)
+      doAssert d.len == 0
+
     when not defined(testing):
       echo "Micro tests run successfully."
 
diff --git a/lib/pure/collections/sharedtables.nim b/lib/pure/collections/sharedtables.nim
index 0292a27a2..6ebb00e57 100644
--- a/lib/pure/collections/sharedtables.nim
+++ b/lib/pure/collections/sharedtables.nim
@@ -29,6 +29,14 @@ template maxHash(t): untyped = t.dataLen-1
 
 include tableimpl
 
+template st_maybeRehashPutImpl(enlarge) {.dirty.} =
+  if mustRehash(t.dataLen, t.counter):
+    enlarge(t)
+    index = rawGetKnownHC(t, key, hc)
+  index = -1 - index                  # important to transform for mgetOrPutImpl
+  rawInsert(t, t.data, key, val, hc, index)
+  inc(t.counter)
+
 proc enlarge[A, B](t: var SharedTable[A, B]) =
   let oldSize = t.dataLen
   let size = oldSize * growthFactor
@@ -176,7 +184,7 @@ proc withKey*[A, B](t: var SharedTable[A, B], key: A,
       var val: B
       mapper(key, val, pairExists)
       if pairExists:
-        maybeRehashPutImpl(enlarge)
+        st_maybeRehashPutImpl(enlarge)
 
 proc `[]=`*[A, B](t: var SharedTable[A, B], key: A, val: B) =
   ## puts a (key, value)-pair into `t`.
diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim
index 3e34b1488..4f9610db3 100644
--- a/lib/pure/collections/tableimpl.nim
+++ b/lib/pure/collections/tableimpl.nim
@@ -9,49 +9,7 @@
 
 # An ``include`` file for the different table implementations.
 
-# hcode for real keys cannot be zero.  hcode==0 signifies an empty slot.  These
-# two procs retain clarity of that encoding without the space cost of an enum.
-proc isEmpty(hcode: Hash): bool {.inline.} =
-  result = hcode == 0
-
-proc isFilled(hcode: Hash): bool {.inline.} =
-  result = hcode != 0
-
-const
-  growthFactor = 2
-
-proc mustRehash(length, counter: int): bool {.inline.} =
-  assert(length > counter)
-  result = (length * 2 < counter * 3) or (length - counter < 4)
-
-proc nextTry(h, maxHash: Hash): Hash {.inline.} =
-  result = (h + 1) and maxHash
-
-template rawGetKnownHCImpl() {.dirty.} =
-  var h: Hash = hc and maxHash(t)   # start with real hash value
-  while isFilled(t.data[h].hcode):
-    # Compare hc THEN key with boolean short circuit. This makes the common case
-    # zero ==key's for missing (e.g.inserts) and exactly one ==key for present.
-    # It does slow down succeeding lookups by one extra Hash cmp&and..usually
-    # just a few clock cycles, generally worth it for any non-integer-like A.
-    if t.data[h].hcode == hc and t.data[h].key == key:
-      return h
-    h = nextTry(h, maxHash(t))
-  result = -1 - h                   # < 0 => MISSING; insert idx = -1 - result
-
-template genHashImpl(key, hc: typed) =
-  hc = hash(key)
-  if hc == 0:       # This almost never taken branch should be very predictable.
-    hc = 314159265  # Value doesn't matter; Any non-zero favorite is fine.
-
-template genHash(key: typed): Hash =
-  var res: Hash
-  genHashImpl(key, res)
-  res
-
-template rawGetImpl() {.dirty.} =
-  genHashImpl(key, hc)
-  rawGetKnownHCImpl()
+include hashcommon
 
 template rawGetDeepImpl() {.dirty.} =   # Search algo for unconditional add
   genHashImpl(key, hc)
@@ -65,20 +23,16 @@ template rawInsertImpl() {.dirty.} =
   data[h].val = val
   data[h].hcode = hc
 
-proc rawGetKnownHC[X, A](t: X, key: A, hc: Hash): int {.inline.} =
-  rawGetKnownHCImpl()
-
 proc rawGetDeep[X, A](t: X, key: A, hc: var Hash): int {.inline.} =
   rawGetDeepImpl()
 
-proc rawGet[X, A](t: X, key: A, hc: var Hash): int {.inline.} =
-  rawGetImpl()
-
 proc rawInsert[X, A, B](t: var X, data: var KeyValuePairSeq[A, B],
                      key: A, val: B, hc: Hash, h: Hash) =
   rawInsertImpl()
 
 template addImpl(enlarge) {.dirty.} =
+  if t.dataLen == 0:
+    initImpl(t, defaultInitialSize)
   if mustRehash(t.dataLen, t.counter): enlarge(t)
   var hc: Hash
   var j = rawGetDeep(t, key, hc)
@@ -86,6 +40,8 @@ template addImpl(enlarge) {.dirty.} =
   inc(t.counter)
 
 template maybeRehashPutImpl(enlarge) {.dirty.} =
+  if t.dataLen == 0:
+    initImpl(t, defaultInitialSize)
   if mustRehash(t.dataLen, t.counter):
     enlarge(t)
     index = rawGetKnownHC(t, key, hc)
@@ -94,12 +50,16 @@ template maybeRehashPutImpl(enlarge) {.dirty.} =
   inc(t.counter)
 
 template putImpl(enlarge) {.dirty.} =
+  if t.dataLen == 0:
+    initImpl(t, defaultInitialSize)
   var hc: Hash
   var index = rawGet(t, key, hc)
   if index >= 0: t.data[index].val = val
   else: maybeRehashPutImpl(enlarge)
 
 template mgetOrPutImpl(enlarge) {.dirty.} =
+  if t.dataLen == 0:
+    initImpl(t, defaultInitialSize)
   var hc: Hash
   var index = rawGet(t, key, hc)
   if index < 0:
@@ -109,6 +69,8 @@ template mgetOrPutImpl(enlarge) {.dirty.} =
   result = t.data[index].val
 
 template hasKeyOrPutImpl(enlarge) {.dirty.} =
+  if t.dataLen == 0:
+    initImpl(t, defaultInitialSize)
   var hc: Hash
   var index = rawGet(t, key, hc)
   if index < 0:
@@ -116,11 +78,6 @@ template hasKeyOrPutImpl(enlarge) {.dirty.} =
     maybeRehashPutImpl(enlarge)
   else: result = true
 
-when not defined(nimHasDefault):
-  template default[T](t: typedesc[T]): T =
-    var v: T
-    v
-
 template delImplIdx(t, i) =
   let msk = maxHash(t)
   if i >= 0:
@@ -150,9 +107,53 @@ template delImpl() {.dirty.} =
   delImplIdx(t, i)
 
 template clearImpl() {.dirty.} =
-  for i in 0 ..< t.data.len:
+  for i in 0 ..< t.dataLen:
     when compiles(t.data[i].hcode): # CountTable records don't contain a hcode
       t.data[i].hcode = 0
     t.data[i].key = default(type(t.data[i].key))
     t.data[i].val = default(type(t.data[i].val))
   t.counter = 0
+
+template initImpl(result: typed, size: int) =
+  assert isPowerOfTwo(size)
+  result.counter = 0
+  newSeq(result.data, size)
+
+template insertImpl() = # for CountTable
+  if t.dataLen == 0: initImpl(t, defaultInitialSize)
+  if mustRehash(len(t.data), t.counter): enlarge(t)
+  ctRawInsert(t, t.data, key, val)
+  inc(t.counter)
+
+template getOrDefaultImpl(t, key): untyped =
+  mixin rawGet
+  var hc: Hash
+  var index = rawGet(t, key, hc)
+  if index >= 0: result = t.data[index].val
+
+template getOrDefaultImpl(t, key, default: untyped): untyped =
+  mixin rawGet
+  var hc: Hash
+  var index = rawGet(t, key, hc)
+  result = if index >= 0: t.data[index].val else: default
+
+template dollarImpl(): untyped {.dirty.} =
+  if t.len == 0:
+    result = "{:}"
+  else:
+    result = "{"
+    for key, val in pairs(t):
+      if result.len > 1: result.add(", ")
+      result.addQuoted(key)
+      result.add(": ")
+      result.addQuoted(val)
+    result.add("}")
+
+template equalsImpl(s, t: typed): typed =
+  if s.counter == t.counter:
+    # different insertion orders mean different 'data' seqs, so we have
+    # to use the slow route here:
+    for key, val in s:
+      if not t.hasKey(key): return false
+      if t.getOrDefault(key) != val: return false
+    return true
diff --git a/lib/pure/collections/tables.nim b/lib/pure/collections/tables.nim
index c6d5cc9e2..98ece4779 100644
--- a/lib/pure/collections/tables.nim
+++ b/lib/pure/collections/tables.nim
@@ -19,7 +19,7 @@
 ## For consistency with every other data type in Nim these have **value**
 ## semantics, this means that ``=`` performs a copy of the hash table.
 ##
-## For `ref semantics<manual.html#types-ref-and-pointer-types>`_
+## For `ref semantics<manual.html#types-reference-and-pointer-types>`_
 ## use their ``Ref`` variants: `TableRef<#TableRef>`_,
 ## `OrderedTableRef<#OrderedTableRef>`_, and `CountTableRef<#CountTableRef>`_.
 ##
@@ -237,9 +237,13 @@ type
     ## For creating a new empty TableRef, use `newTable proc
     ## <#newTable,int>`_.
 
+const
+  defaultInitialSize* = 64
 
 # ------------------------------ helpers ---------------------------------
 
+# Do NOT move these to tableimpl.nim, because sharedtables uses that
+# file and has its own implementation.
 template maxHash(t): untyped = high(t.data)
 template dataLen(t): untyped = len(t.data)
 
@@ -260,30 +264,6 @@ template get(t, key): untyped =
     else:
       raise newException(KeyError, "key not found")
 
-template getOrDefaultImpl(t, key): untyped =
-  mixin rawGet
-  var hc: Hash
-  var index = rawGet(t, key, hc)
-  if index >= 0: result = t.data[index].val
-
-template getOrDefaultImpl(t, key, default: untyped): untyped =
-  mixin rawGet
-  var hc: Hash
-  var index = rawGet(t, key, hc)
-  result = if index >= 0: t.data[index].val else: default
-
-template dollarImpl(): untyped {.dirty.} =
-  if t.len == 0:
-    result = "{:}"
-  else:
-    result = "{"
-    for key, val in pairs(t):
-      if result.len > 1: result.add(", ")
-      result.addQuoted(key)
-      result.add(": ")
-      result.addQuoted(val)
-    result.add("}")
-
 proc enlarge[A, B](t: var Table[A, B]) =
   var n: KeyValuePairSeq[A, B]
   newSeq(n, len(t.data) * growthFactor)
@@ -294,16 +274,8 @@ proc enlarge[A, B](t: var Table[A, B]) =
       var j: Hash = eh and maxHash(t)
       while isFilled(t.data[j].hcode):
         j = nextTry(j, maxHash(t))
-      rawInsert(t, t.data, n[i].key, n[i].val, eh, j)
+      rawInsert(t, t.data, move n[i].key, move n[i].val, eh, j)
 
-template equalsImpl(s, t: typed): typed =
-  if s.counter == t.counter:
-    # different insertion orders mean different 'data' seqs, so we have
-    # to use the slow route here:
-    for key, val in s:
-      if not t.hasKey(key): return false
-      if t.getOrDefault(key) != val: return false
-    return true
 
 
 
@@ -311,7 +283,7 @@ template equalsImpl(s, t: typed): typed =
 # ------------------------------ Table ------------------------------
 # -------------------------------------------------------------------
 
-proc initTable*[A, B](initialSize=64): Table[A, B] =
+proc initTable*[A, B](initialsize = defaultInitialSize): Table[A, B] =
   ## Creates a new hash table that is empty.
   ##
   ## ``initialSize`` must be a power of two (default: 64).
@@ -320,6 +292,9 @@ proc initTable*[A, B](initialSize=64): Table[A, B] =
   ## `math module<math.html>`_ or the `rightSize proc<#rightSize,Natural>`_
   ## from this module.
   ##
+  ## Starting from Nim v0.20, tables are initialized by default and it is
+  ## not necessary to call this function explicitly.
+  ##
   ## See also:
   ## * `toTable proc<#toTable,openArray[]>`_
   ## * `newTable proc<#newTable,int>`_ for creating a `TableRef`
@@ -327,9 +302,7 @@ proc initTable*[A, B](initialSize=64): Table[A, B] =
     let
       a = initTable[int, string]()
       b = initTable[char, seq[int]]()
-  assert isPowerOfTwo(initialSize)
-  result.counter = 0
-  newSeq(result.data, initialSize)
+  initImpl(result, initialSize)
 
 proc toTable*[A, B](pairs: openArray[(A, B)]): Table[A, B] =
   ## Creates a new hash table that contains the given ``pairs``.
@@ -343,6 +316,7 @@ proc toTable*[A, B](pairs: openArray[(A, B)]): Table[A, B] =
     let a = [('a', 5), ('b', 9)]
     let b = toTable(a)
     assert b == {'a': 5, 'b': 9}.toTable
+
   result = initTable[A, B](rightSize(pairs.len))
   for key, val in items(pairs): result[key] = val
 
@@ -398,6 +372,7 @@ proc `[]=`*[A, B](t: var Table[A, B], key: A, val: B) =
     a['x'] = 7
     a['y'] = 33
     doAssert a == {'x': 7, 'y': 33}.toTable
+
   putImpl(enlarge)
 
 proc hasKey*[A, B](t: Table[A, B], key: A): bool =
@@ -414,6 +389,7 @@ proc hasKey*[A, B](t: Table[A, B], key: A): bool =
     let a = {'a': 5, 'b': 9}.toTable
     doAssert a.hasKey('a') == true
     doAssert a.hasKey('z') == false
+
   var hc: Hash
   result = rawGet(t, key, hc) >= 0
 
@@ -424,6 +400,7 @@ proc contains*[A, B](t: Table[A, B], key: A): bool =
     let a = {'a': 5, 'b': 9}.toTable
     doAssert 'b' in a == true
     doAssert a.contains('z') == false
+
   return hasKey[A, B](t, key)
 
 proc hasKeyOrPut*[A, B](t: var Table[A, B], key: A, val: B): bool =
@@ -443,6 +420,7 @@ proc hasKeyOrPut*[A, B](t: var Table[A, B], key: A, val: B): bool =
     if a.hasKeyOrPut('z', 50):
       a['z'] = 99
     doAssert a == {'a': 99, 'b': 9, 'z': 50}.toTable
+
   hasKeyOrPutImpl(enlarge)
 
 proc getOrDefault*[A, B](t: Table[A, B], key: A): B =
@@ -461,6 +439,7 @@ proc getOrDefault*[A, B](t: Table[A, B], key: A): B =
     let a = {'a': 5, 'b': 9}.toTable
     doAssert a.getOrDefault('a') == 5
     doAssert a.getOrDefault('z') == 0
+
   getOrDefaultImpl(t, key)
 
 proc getOrDefault*[A, B](t: Table[A, B], key: A, default: B): B =
@@ -478,6 +457,7 @@ proc getOrDefault*[A, B](t: Table[A, B], key: A, default: B): B =
     let a = {'a': 5, 'b': 9}.toTable
     doAssert a.getOrDefault('a', 99) == 5
     doAssert a.getOrDefault('z', 99) == 99
+
   getOrDefaultImpl(t, key, default)
 
 proc mgetOrPut*[A, B](t: var Table[A, B], key: A, val: B): var B =
@@ -497,6 +477,7 @@ proc mgetOrPut*[A, B](t: var Table[A, B], key: A, val: B): var B =
     doAssert a.mgetOrPut('a', 99) == 5
     doAssert a.mgetOrPut('z', 99) == 99
     doAssert a == {'a': 5, 'b': 9, 'z': 99}.toTable
+
   mgetOrPutImpl(enlarge)
 
 proc len*[A, B](t: Table[A, B]): int =
@@ -504,6 +485,7 @@ proc len*[A, B](t: Table[A, B]): int =
   runnableExamples:
     let a = {'a': 5, 'b': 9}.toTable
     doAssert len(a) == 2
+
   result = t.counter
 
 proc add*[A, B](t: var Table[A, B], key: A, val: B) =
@@ -527,6 +509,7 @@ proc del*[A, B](t: var Table[A, B], key: A) =
     doAssert a == {'b': 9, 'c': 13}.toTable
     a.del('z')
     doAssert a == {'b': 9, 'c': 13}.toTable
+
   delImpl()
 
 proc take*[A, B](t: var Table[A, B], key: A, val: var B): bool =
@@ -568,6 +551,7 @@ proc clear*[A, B](t: var Table[A, B]) =
     doAssert len(a) == 3
     clear(a)
     doAssert len(a) == 0
+
   clearImpl()
 
 proc `$`*[A, B](t: Table[A, B]): string =
@@ -583,6 +567,7 @@ proc `==`*[A, B](s, t: Table[A, B]): bool =
       a = {'a': 5, 'b': 9, 'c': 13}.toTable
       b = {'b': 9, 'c': 13, 'a': 5}.toTable
     doAssert a == b
+
   equalsImpl(s, t)
 
 proc rightSize*(count: Natural): int {.inline.} =
@@ -692,6 +677,7 @@ iterator mpairs*[A, B](t: var Table[A, B]): (A, var B) =
     for k, v in a.mpairs:
       v.add(v[0] + 10)
     doAssert a == {'e': @[2, 4, 6, 8, 12], 'o': @[1, 5, 7, 9, 11]}.toTable
+
   for h in 0..high(t.data):
     if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
 
@@ -709,6 +695,7 @@ iterator keys*[A, B](t: Table[A, B]): A =
     for k in a.keys:
       a[k].add(99)
     doAssert a == {'e': @[2, 4, 6, 8, 99], 'o': @[1, 5, 7, 9, 99]}.toTable
+
   for h in 0..high(t.data):
     if isFilled(t.data[h].hcode): yield t.data[h].key
 
@@ -726,6 +713,7 @@ iterator values*[A, B](t: Table[A, B]): B =
       }.toTable
     for v in a.values:
       doAssert v.len == 4
+
   for h in 0..high(t.data):
     if isFilled(t.data[h].hcode): yield t.data[h].val
 
@@ -744,6 +732,7 @@ iterator mvalues*[A, B](t: var Table[A, B]): var B =
     for v in a.mvalues:
       v.add(99)
     doAssert a == {'e': @[2, 4, 6, 8, 99], 'o': @[1, 5, 7, 9, 99]}.toTable
+
   for h in 0..high(t.data):
     if isFilled(t.data[h].hcode): yield t.data[h].val
 
@@ -779,7 +768,7 @@ iterator allValues*[A, B](t: Table[A, B]; key: A): B =
 # -------------------------------------------------------------------
 
 
-proc newTable*[A, B](initialSize=64): TableRef[A, B] =
+proc newTable*[A, B](initialsize = defaultInitialSize): <//>TableRef[A, B] =
   ## Creates a new ref hash table that is empty.
   ##
   ## ``initialSize`` must be a power of two (default: 64).
@@ -796,10 +785,11 @@ proc newTable*[A, B](initialSize=64): TableRef[A, B] =
     let
       a = newTable[int, string]()
       b = newTable[char, seq[int]]()
+
   new(result)
   result[] = initTable[A, B](initialSize)
 
-proc newTable*[A, B](pairs: openArray[(A, B)]): TableRef[A, B] =
+proc newTable*[A, B](pairs: openArray[(A, B)]): <//>TableRef[A, B] =
   ## Creates a new ref hash table that contains the given ``pairs``.
   ##
   ## ``pairs`` is a container consisting of ``(key, value)`` tuples.
@@ -811,10 +801,11 @@ proc newTable*[A, B](pairs: openArray[(A, B)]): TableRef[A, B] =
     let a = [('a', 5), ('b', 9)]
     let b = newTable(a)
     assert b == {'a': 5, 'b': 9}.newTable
+
   new(result)
   result[] = toTable[A, B](pairs)
 
-proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): TableRef[C, B] =
+proc newTableFrom*[A, B, C](collection: A, index: proc(x: B): C): <//>TableRef[C, B] =
   ## Index the collection with the proc provided.
   # TODO: As soon as supported, change collection: A to collection: A[B]
   result = newTable[C, B]()
@@ -842,6 +833,7 @@ proc `[]`*[A, B](t: TableRef[A, B], key: A): var B =
     doAssert a['a'] == 5
     doAssertRaises(KeyError):
       echo a['z']
+
   result = t[][key]
 
 proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: B) =
@@ -857,6 +849,7 @@ proc `[]=`*[A, B](t: TableRef[A, B], key: A, val: B) =
     a['x'] = 7
     a['y'] = 33
     doAssert a == {'x': 7, 'y': 33}.newTable
+
   t[][key] = val
 
 proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
@@ -874,6 +867,7 @@ proc hasKey*[A, B](t: TableRef[A, B], key: A): bool =
     let a = {'a': 5, 'b': 9}.newTable
     doAssert a.hasKey('a') == true
     doAssert a.hasKey('z') == false
+
   result = t[].hasKey(key)
 
 proc contains*[A, B](t: TableRef[A, B], key: A): bool =
@@ -883,6 +877,7 @@ proc contains*[A, B](t: TableRef[A, B], key: A): bool =
     let a = {'a': 5, 'b': 9}.newTable
     doAssert 'b' in a == true
     doAssert a.contains('z') == false
+
   return hasKey[A, B](t, key)
 
 proc hasKeyOrPut*[A, B](t: var TableRef[A, B], key: A, val: B): bool =
@@ -902,6 +897,7 @@ proc hasKeyOrPut*[A, B](t: var TableRef[A, B], key: A, val: B): bool =
     if a.hasKeyOrPut('z', 50):
       a['z'] = 99
     doAssert a == {'a': 99, 'b': 9, 'z': 50}.newTable
+
   t[].hasKeyOrPut(key, val)
 
 proc getOrDefault*[A, B](t: TableRef[A, B], key: A): B =
@@ -920,6 +916,7 @@ proc getOrDefault*[A, B](t: TableRef[A, B], key: A): B =
     let a = {'a': 5, 'b': 9}.newTable
     doAssert a.getOrDefault('a') == 5
     doAssert a.getOrDefault('z') == 0
+
   getOrDefault(t[], key)
 
 proc getOrDefault*[A, B](t: TableRef[A, B], key: A, default: B): B =
@@ -937,6 +934,7 @@ proc getOrDefault*[A, B](t: TableRef[A, B], key: A, default: B): B =
     let a = {'a': 5, 'b': 9}.newTable
     doAssert a.getOrDefault('a', 99) == 5
     doAssert a.getOrDefault('z', 99) == 99
+
   getOrDefault(t[], key, default)
 
 proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B =
@@ -956,6 +954,7 @@ proc mgetOrPut*[A, B](t: TableRef[A, B], key: A, val: B): var B =
     doAssert a.mgetOrPut('a', 99) == 5
     doAssert a.mgetOrPut('z', 99) == 99
     doAssert a == {'a': 5, 'b': 9, 'z': 99}.newTable
+
   t[].mgetOrPut(key, val)
 
 proc len*[A, B](t: TableRef[A, B]): int =
@@ -963,6 +962,7 @@ proc len*[A, B](t: TableRef[A, B]): int =
   runnableExamples:
     let a = {'a': 5, 'b': 9}.newTable
     doAssert len(a) == 2
+
   result = t.counter
 
 proc add*[A, B](t: TableRef[A, B], key: A, val: B) =
@@ -988,6 +988,7 @@ proc del*[A, B](t: TableRef[A, B], key: A) =
     doAssert a == {'b': 9, 'c': 13}.newTable
     a.del('z')
     doAssert a == {'b': 9, 'c': 13}.newTable
+
   t[].del(key)
 
 proc take*[A, B](t: TableRef[A, B], key: A, val: var B): bool =
@@ -1012,6 +1013,7 @@ proc take*[A, B](t: TableRef[A, B], key: A, val: var B): bool =
     doAssert a.take('z', i) == false
     doAssert a == {'a': 5, 'c': 13}.newTable
     doAssert i == 0
+
   result = t[].take(key, val)
 
 proc clear*[A, B](t: TableRef[A, B]) =
@@ -1025,6 +1027,7 @@ proc clear*[A, B](t: TableRef[A, B]) =
     doAssert len(a) == 3
     clear(a)
     doAssert len(a) == 0
+
   clearImpl()
 
 proc `$`*[A, B](t: TableRef[A, B]): string =
@@ -1041,6 +1044,7 @@ proc `==`*[A, B](s, t: TableRef[A, B]): bool =
       a = {'a': 5, 'b': 9, 'c': 13}.newTable
       b = {'b': 9, 'c': 13, 'a': 5}.newTable
     doAssert a == b
+
   if isNil(s): result = isNil(t)
   elif isNil(t): result = false
   else: equalsImpl(s[], t[])
@@ -1089,6 +1093,7 @@ iterator mpairs*[A, B](t: TableRef[A, B]): (A, var B) =
     for k, v in a.mpairs:
       v.add(v[0] + 10)
     doAssert a == {'e': @[2, 4, 6, 8, 12], 'o': @[1, 5, 7, 9, 11]}.newTable
+
   for h in 0..high(t.data):
     if isFilled(t.data[h].hcode): yield (t.data[h].key, t.data[h].val)
 
@@ -1106,6 +1111,7 @@ iterator keys*[A, B](t: TableRef[A, B]): A =
     for k in a.keys:
       a[k].add(99)
     doAssert a == {'e': @[2, 4, 6, 8, 99], 'o': @[1, 5, 7, 9, 99]}.newTable
+
   for h in 0..high(t.data):
     if isFilled(t.data[h].hcode): yield t.data[h].key
 
@@ -1123,6 +1129,7 @@ iterator values*[A, B](t: TableRef[A, B]): B =
       }.newTable
     for v in a.values:
       doAssert v.len == 4
+
   for h in 0..high(t.data):
     if isFilled(t.data[h].hcode): yield t.data[h].val
 
@@ -1140,6 +1147,7 @@ iterator mvalues*[A, B](t: TableRef[A, B]): var B =
     for v in a.mvalues:
       v.add(99)
     doAssert a == {'e': @[2, 4, 6, 8, 99], 'o': @[1, 5, 7, 9, 99]}.newTable
+
   for h in 0..high(t.data):
     if isFilled(t.data[h].hcode): yield t.data[h].val
 
@@ -1218,7 +1226,7 @@ template forAllOrderedPairs(yieldStmt: untyped): typed {.dirty.} =
 
 # ----------------------------------------------------------------------
 
-proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] =
+proc initOrderedTable*[A, B](initialsize = defaultInitialSize): OrderedTable[A, B] =
   ## Creates a new ordered hash table that is empty.
   ##
   ## ``initialSize`` must be a power of two (default: 64).
@@ -1227,6 +1235,9 @@ proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] =
   ## `math module<math.html>`_ or the `rightSize proc<#rightSize,Natural>`_
   ## from this module.
   ##
+  ## Starting from Nim v0.20, tables are initialized by default and it is
+  ## not necessary to call this function explicitly.
+  ##
   ## See also:
   ## * `toOrderedTable proc<#toOrderedTable,openArray[]>`_
   ## * `newOrderedTable proc<#newOrderedTable,int>`_ for creating an
@@ -1235,11 +1246,9 @@ proc initOrderedTable*[A, B](initialSize=64): OrderedTable[A, B] =
     let
       a = initOrderedTable[int, string]()
       b = initOrderedTable[char, seq[int]]()
-  assert isPowerOfTwo(initialSize)
-  result.counter = 0
+  initImpl(result, initialSize)
   result.first = -1
   result.last = -1
-  newSeq(result.data, initialSize)
 
 proc toOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTable[A, B] =
   ## Creates a new ordered hash table that contains the given ``pairs``.
@@ -1254,6 +1263,7 @@ proc toOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTable[A, B] =
     let a = [('a', 5), ('b', 9)]
     let b = toOrderedTable(a)
     assert b == {'a': 5, 'b': 9}.toOrderedTable
+
   result = initOrderedTable[A, B](rightSize(pairs.len))
   for key, val in items(pairs): result[key] = val
 
@@ -1278,6 +1288,7 @@ proc `[]`*[A, B](t: OrderedTable[A, B], key: A): B =
     doAssert a['a'] == 5
     doAssertRaises(KeyError):
       echo a['z']
+
   get(t, key)
 
 proc `[]`*[A, B](t: var OrderedTable[A, B], key: A): var B=
@@ -1309,6 +1320,7 @@ proc `[]=`*[A, B](t: var OrderedTable[A, B], key: A, val: B) =
     a['x'] = 7
     a['y'] = 33
     doAssert a == {'x': 7, 'y': 33}.toOrderedTable
+
   putImpl(enlarge)
 
 proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
@@ -1326,6 +1338,7 @@ proc hasKey*[A, B](t: OrderedTable[A, B], key: A): bool =
     let a = {'a': 5, 'b': 9}.toOrderedTable
     doAssert a.hasKey('a') == true
     doAssert a.hasKey('z') == false
+
   var hc: Hash
   result = rawGet(t, key, hc) >= 0
 
@@ -1336,6 +1349,7 @@ proc contains*[A, B](t: OrderedTable[A, B], key: A): bool =
     let a = {'a': 5, 'b': 9}.toOrderedTable
     doAssert 'b' in a == true
     doAssert a.contains('z') == false
+
   return hasKey[A, B](t, key)
 
 proc hasKeyOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): bool =
@@ -1355,6 +1369,7 @@ proc hasKeyOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): bool =
     if a.hasKeyOrPut('z', 50):
       a['z'] = 99
     doAssert a == {'a': 99, 'b': 9, 'z': 50}.toOrderedTable
+
   hasKeyOrPutImpl(enlarge)
 
 proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A): B =
@@ -1373,6 +1388,7 @@ proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A): B =
     let a = {'a': 5, 'b': 9}.toOrderedTable
     doAssert a.getOrDefault('a') == 5
     doAssert a.getOrDefault('z') == 0
+
   getOrDefaultImpl(t, key)
 
 proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A, default: B): B =
@@ -1390,6 +1406,7 @@ proc getOrDefault*[A, B](t: OrderedTable[A, B], key: A, default: B): B =
     let a = {'a': 5, 'b': 9}.toOrderedTable
     doAssert a.getOrDefault('a', 99) == 5
     doAssert a.getOrDefault('z', 99) == 99
+
   getOrDefaultImpl(t, key, default)
 
 proc mgetOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): var B =
@@ -1409,6 +1426,7 @@ proc mgetOrPut*[A, B](t: var OrderedTable[A, B], key: A, val: B): var B =
     doAssert a.mgetOrPut('a', 99) == 5
     doAssert a.mgetOrPut('z', 99) == 99
     doAssert a == {'a': 5, 'b': 9, 'z': 99}.toOrderedTable
+
   mgetOrPutImpl(enlarge)
 
 proc len*[A, B](t: OrderedTable[A, B]): int {.inline.} =
@@ -1416,6 +1434,7 @@ proc len*[A, B](t: OrderedTable[A, B]): int {.inline.} =
   runnableExamples:
     let a = {'a': 5, 'b': 9}.toOrderedTable
     doAssert len(a) == 2
+
   result = t.counter
 
 proc add*[A, B](t: var OrderedTable[A, B], key: A, val: B) =
@@ -1440,6 +1459,7 @@ proc del*[A, B](t: var OrderedTable[A, B], key: A) =
     doAssert a == {'b': 9, 'c': 13}.toOrderedTable
     a.del('z')
     doAssert a == {'b': 9, 'c': 13}.toOrderedTable
+
   var n: OrderedKeyValuePairSeq[A, B]
   newSeq(n, len(t.data))
   var h = t.first
@@ -1467,6 +1487,7 @@ proc clear*[A, B](t: var OrderedTable[A, B]) =
     doAssert len(a) == 3
     clear(a)
     doAssert len(a) == 0
+
   clearImpl()
   t.first = -1
   t.last = -1
@@ -1602,6 +1623,7 @@ iterator mpairs*[A, B](t: var OrderedTable[A, B]): (A, var B) =
     for k, v in a.mpairs:
       v.add(v[0] + 10)
     doAssert a == {'o': @[1, 5, 7, 9, 11], 'e': @[2, 4, 6, 8, 12]}.toOrderedTable
+
   forAllOrderedPairs:
     yield (t.data[h].key, t.data[h].val)
 
@@ -1619,6 +1641,7 @@ iterator keys*[A, B](t: OrderedTable[A, B]): A =
     for k in a.keys:
       a[k].add(99)
     doAssert a == {'o': @[1, 5, 7, 9, 99], 'e': @[2, 4, 6, 8, 99]}.toOrderedTable
+
   forAllOrderedPairs:
     yield t.data[h].key
 
@@ -1636,6 +1659,7 @@ iterator values*[A, B](t: OrderedTable[A, B]): B =
       }.toOrderedTable
     for v in a.values:
       doAssert v.len == 4
+
   forAllOrderedPairs:
     yield t.data[h].val
 
@@ -1666,7 +1690,7 @@ iterator mvalues*[A, B](t: var OrderedTable[A, B]): var B =
 # --------------------------- OrderedTableRef -------------------------------
 # ---------------------------------------------------------------------------
 
-proc newOrderedTable*[A, B](initialSize=64): OrderedTableRef[A, B] =
+proc newOrderedTable*[A, B](initialsize = defaultInitialSize): <//>OrderedTableRef[A, B] =
   ## Creates a new ordered ref hash table that is empty.
   ##
   ## ``initialSize`` must be a power of two (default: 64).
@@ -1687,7 +1711,7 @@ proc newOrderedTable*[A, B](initialSize=64): OrderedTableRef[A, B] =
   new(result)
   result[] = initOrderedTable[A, B](initialSize)
 
-proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] =
+proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): <//>OrderedTableRef[A, B] =
   ## Creates a new ordered ref hash table that contains the given ``pairs``.
   ##
   ## ``pairs`` is a container consisting of ``(key, value)`` tuples.
@@ -1700,6 +1724,7 @@ proc newOrderedTable*[A, B](pairs: openArray[(A, B)]): OrderedTableRef[A, B] =
     let a = [('a', 5), ('b', 9)]
     let b = newOrderedTable(a)
     assert b == {'a': 5, 'b': 9}.newOrderedTable
+
   result = newOrderedTable[A, B](rightSize(pairs.len))
   for key, val in items(pairs): result.add(key, val)
 
@@ -1740,6 +1765,7 @@ proc `[]=`*[A, B](t: OrderedTableRef[A, B], key: A, val: B) =
     a['x'] = 7
     a['y'] = 33
     doAssert a == {'x': 7, 'y': 33}.newOrderedTable
+
   t[][key] = val
 
 proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool =
@@ -1757,6 +1783,7 @@ proc hasKey*[A, B](t: OrderedTableRef[A, B], key: A): bool =
     let a = {'a': 5, 'b': 9}.newOrderedTable
     doAssert a.hasKey('a') == true
     doAssert a.hasKey('z') == false
+
   result = t[].hasKey(key)
 
 proc contains*[A, B](t: OrderedTableRef[A, B], key: A): bool =
@@ -1766,6 +1793,7 @@ proc contains*[A, B](t: OrderedTableRef[A, B], key: A): bool =
     let a = {'a': 5, 'b': 9}.newOrderedTable
     doAssert 'b' in a == true
     doAssert a.contains('z') == false
+
   return hasKey[A, B](t, key)
 
 proc hasKeyOrPut*[A, B](t: var OrderedTableRef[A, B], key: A, val: B): bool =
@@ -1785,6 +1813,7 @@ proc hasKeyOrPut*[A, B](t: var OrderedTableRef[A, B], key: A, val: B): bool =
     if a.hasKeyOrPut('z', 50):
       a['z'] = 99
     doAssert a == {'a': 99, 'b': 9, 'z': 50}.newOrderedTable
+
   result = t[].hasKeyOrPut(key, val)
 
 proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A): B =
@@ -1803,6 +1832,7 @@ proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A): B =
     let a = {'a': 5, 'b': 9}.newOrderedTable
     doAssert a.getOrDefault('a') == 5
     doAssert a.getOrDefault('z') == 0
+
   getOrDefault(t[], key)
 
 proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A, default: B): B =
@@ -1820,6 +1850,7 @@ proc getOrDefault*[A, B](t: OrderedTableRef[A, B], key: A, default: B): B =
     let a = {'a': 5, 'b': 9}.newOrderedTable
     doAssert a.getOrDefault('a', 99) == 5
     doAssert a.getOrDefault('z', 99) == 99
+
   getOrDefault(t[], key, default)
 
 proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): var B =
@@ -1839,6 +1870,7 @@ proc mgetOrPut*[A, B](t: OrderedTableRef[A, B], key: A, val: B): var B =
     doAssert a.mgetOrPut('a', 99) == 5
     doAssert a.mgetOrPut('z', 99) == 99
     doAssert a == {'a': 5, 'b': 9, 'z': 99}.newOrderedTable
+
   result = t[].mgetOrPut(key, val)
 
 proc len*[A, B](t: OrderedTableRef[A, B]): int {.inline.} =
@@ -1846,6 +1878,7 @@ proc len*[A, B](t: OrderedTableRef[A, B]): int {.inline.} =
   runnableExamples:
     let a = {'a': 5, 'b': 9}.newOrderedTable
     doAssert len(a) == 2
+
   result = t.counter
 
 proc add*[A, B](t: OrderedTableRef[A, B], key: A, val: B) =
@@ -1868,6 +1901,7 @@ proc del*[A, B](t: var OrderedTableRef[A, B], key: A) =
     doAssert a == {'b': 9, 'c': 13}.newOrderedTable
     a.del('z')
     doAssert a == {'b': 9, 'c': 13}.newOrderedTable
+
   t[].del(key)
 
 proc clear*[A, B](t: var OrderedTableRef[A, B]) =
@@ -1880,6 +1914,7 @@ proc clear*[A, B](t: var OrderedTableRef[A, B]) =
     doAssert len(a) == 3
     clear(a)
     doAssert len(a) == 0
+
   clear(t[])
 
 proc sort*[A, B](t: OrderedTableRef[A, B], cmp: proc (x,y: (A, B)): int, order = SortOrder.Ascending) =
@@ -1899,6 +1934,7 @@ proc sort*[A, B](t: OrderedTableRef[A, B], cmp: proc (x,y: (A, B)): int, order =
     doAssert a == {'a': 10, 'b': 20, 'c': 0}.newOrderedTable
     a.sort(system.cmp, order=SortOrder.Descending)
     doAssert a == {'c': 0, 'b': 20, 'a': 10}.newOrderedTable
+
   t[].sort(cmp, order=order)
 
 proc `$`*[A, B](t: OrderedTableRef[A, B]): string =
@@ -1915,6 +1951,7 @@ proc `==`*[A, B](s, t: OrderedTableRef[A, B]): bool =
       a = {'a': 5, 'b': 9, 'c': 13}.newOrderedTable
       b = {'b': 9, 'c': 13, 'a': 5}.newOrderedTable
     doAssert a != b
+
   if isNil(s): result = isNil(t)
   elif isNil(t): result = false
   else: result = s[] == t[]
@@ -1964,6 +2001,7 @@ iterator mpairs*[A, B](t: OrderedTableRef[A, B]): (A, var B) =
     for k, v in a.mpairs:
       v.add(v[0] + 10)
     doAssert a == {'o': @[1, 5, 7, 9, 11], 'e': @[2, 4, 6, 8, 12]}.newOrderedTable
+
   forAllOrderedPairs:
     yield (t.data[h].key, t.data[h].val)
 
@@ -1981,6 +2019,7 @@ iterator keys*[A, B](t: OrderedTableRef[A, B]): A =
     for k in a.keys:
       a[k].add(99)
     doAssert a == {'o': @[1, 5, 7, 9, 99], 'e': @[2, 4, 6, 8, 99]}.newOrderedTable
+
   forAllOrderedPairs:
     yield t.data[h].key
 
@@ -1998,6 +2037,7 @@ iterator values*[A, B](t: OrderedTableRef[A, B]): B =
       }.newOrderedTable
     for v in a.values:
       doAssert v.len == 4
+
   forAllOrderedPairs:
     yield t.data[h].val
 
@@ -2016,6 +2056,7 @@ iterator mvalues*[A, B](t: OrderedTableRef[A, B]): var B =
     for v in a.mvalues:
       v.add(99)
     doAssert a == {'o': @[1, 5, 7, 9, 99], 'e': @[2, 4, 6, 8, 99]}.newOrderedTable
+
   forAllOrderedPairs:
     yield t.data[h].val
 
@@ -2046,7 +2087,7 @@ type
 
 # ------------------------------ helpers ---------------------------------
 
-proc rawInsert[A](t: CountTable[A], data: var seq[tuple[key: A, val: int]],
+proc ctRawInsert[A](t: CountTable[A], data: var seq[tuple[key: A, val: int]],
                   key: A, val: int) =
   var h: Hash = hash(key) and high(data)
   while data[h].val != 0: h = nextTry(h, high(data))
@@ -2057,10 +2098,12 @@ proc enlarge[A](t: var CountTable[A]) =
   var n: seq[tuple[key: A, val: int]]
   newSeq(n, len(t.data) * growthFactor)
   for i in countup(0, high(t.data)):
-    if t.data[i].val != 0: rawInsert(t, n, t.data[i].key, t.data[i].val)
+    if t.data[i].val != 0: ctRawInsert(t, n, t.data[i].key, t.data[i].val)
   swap(t.data, n)
 
 proc rawGet[A](t: CountTable[A], key: A): int =
+  if t.data.len == 0:
+    return -1
   var h: Hash = hash(key) and high(t.data) # start with real hash value
   while t.data[h].val != 0:
     if t.data[h].key == key: return h
@@ -2075,7 +2118,7 @@ proc inc*[A](t: var CountTable[A], key: A, val = 1)
 
 # ----------------------------------------------------------------------
 
-proc initCountTable*[A](initialSize=64): CountTable[A] =
+proc initCountTable*[A](initialsize = defaultInitialSize): CountTable[A] =
   ## Creates a new count table that is empty.
   ##
   ## ``initialSize`` must be a power of two (default: 64).
@@ -2084,13 +2127,14 @@ proc initCountTable*[A](initialSize=64): CountTable[A] =
   ## `math module<math.html>`_ or the `rightSize proc<#rightSize,Natural>`_
   ## from this module.
   ##
+  ## Starting from Nim v0.20, tables are initialized by default and it is
+  ## not necessary to call this function explicitly.
+  ##
   ## See also:
   ## * `toCountTable proc<#toCountTable,openArray[A]>`_
   ## * `newCountTable proc<#newCountTable,int>`_ for creating a
   ##   `CountTableRef`
-  assert isPowerOfTwo(initialSize)
-  result.counter = 0
-  newSeq(result.data, initialSize)
+  initImpl(result, initialSize)
 
 proc toCountTable*[A](keys: openArray[A]): CountTable[A] =
   ## Creates a new count table with every member of a container ``keys``
@@ -2130,9 +2174,7 @@ proc `[]=`*[A](t: var CountTable[A], key: A, val: int) =
   if h >= 0:
     t.data[h].val = val
   else:
-    if mustRehash(len(t.data), t.counter): enlarge(t)
-    rawInsert(t, t.data, key, val)
-    inc(t.counter)
+    insertImpl()
 
 proc inc*[A](t: var CountTable[A], key: A, val = 1) =
   ## Increments ``t[key]`` by ``val`` (default: 1).
@@ -2141,14 +2183,13 @@ proc inc*[A](t: var CountTable[A], key: A, val = 1) =
     a.inc('a')
     a.inc('b', 10)
     doAssert a == toCountTable("aaabbbbbbbbbbb")
+
   var index = rawGet(t, key)
   if index >= 0:
     inc(t.data[index].val, val)
     if t.data[index].val == 0: dec(t.counter)
   else:
-    if mustRehash(len(t.data), t.counter): enlarge(t)
-    rawInsert(t, t.data, key, val)
-    inc(t.counter)
+    insertImpl()
 
 proc smallest*[A](t: CountTable[A]): tuple[key: A, val: int] =
   ## Returns the ``(key, value)`` pair with the smallest ``val``. Efficiency: O(n)
@@ -2229,6 +2270,7 @@ proc sort*[A](t: var CountTable[A], order = SortOrder.Descending) =
     doAssert toSeq(a.values) == @[5, 2, 2, 1, 1]
     a.sort(SortOrder.Ascending)
     doAssert toSeq(a.values) == @[1, 1, 2, 2, 5]
+
   t.data.sort(cmp=ctCmp, order=order)
 
 proc merge*[A](s: var CountTable[A], t: CountTable[A]) =
@@ -2238,6 +2280,7 @@ proc merge*[A](s: var CountTable[A], t: CountTable[A]) =
     let b = toCountTable("bcc")
     a.merge(b)
     doAssert a == toCountTable("aaabbbccc")
+
   for key, value in t:
     s.inc(key, value)
 
@@ -2248,6 +2291,7 @@ proc merge*[A](s, t: CountTable[A]): CountTable[A] =
       a = toCountTable("aaabbc")
       b = toCountTable("bcc")
     doAssert merge(a, b) == toCountTable("aaabbbccc")
+
   result = initCountTable[A](nextPowerOfTwo(max(s.len, t.len)))
   for table in @[s, t]:
     for key, value in table:
@@ -2306,6 +2350,7 @@ iterator mpairs*[A](t: var CountTable[A]): (A, var int) =
     for k, v in mpairs(a):
       v = 2
     doAssert a == toCountTable("aabbccddrr")
+
   for h in 0..high(t.data):
     if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
 
@@ -2320,6 +2365,7 @@ iterator keys*[A](t: CountTable[A]): A =
     for k in keys(a):
       a[k] = 2
     doAssert a == toCountTable("aabbccddrr")
+
   for h in 0..high(t.data):
     if t.data[h].val != 0: yield t.data[h].key
 
@@ -2334,6 +2380,7 @@ iterator values*[A](t: CountTable[A]): int =
     let a = toCountTable("abracadabra")
     for v in values(a):
       assert v < 10
+
   for h in 0..high(t.data):
     if t.data[h].val != 0: yield t.data[h].val
 
@@ -2349,6 +2396,7 @@ iterator mvalues*[A](t: var CountTable[A]): var int =
     for v in mvalues(a):
       v = 2
     doAssert a == toCountTable("aabbccddrr")
+
   for h in 0..high(t.data):
     if t.data[h].val != 0: yield t.data[h].val
 
@@ -2364,7 +2412,7 @@ iterator mvalues*[A](t: var CountTable[A]): var int =
 
 proc inc*[A](t: CountTableRef[A], key: A, val = 1)
 
-proc newCountTable*[A](initialSize=64): CountTableRef[A] =
+proc newCountTable*[A](initialsize = defaultInitialSize): <//>CountTableRef[A] =
   ## Creates a new ref count table that is empty.
   ##
   ## ``initialSize`` must be a power of two (default: 64).
@@ -2381,7 +2429,7 @@ proc newCountTable*[A](initialSize=64): CountTableRef[A] =
   new(result)
   result[] = initCountTable[A](initialSize)
 
-proc newCountTable*[A](keys: openArray[A]): CountTableRef[A] =
+proc newCountTable*[A](keys: openArray[A]): <//>CountTableRef[A] =
   ## Creates a new ref count table with every member of a container ``keys``
   ## having a count of how many times it occurs in that container.
   result = newCountTable[A](rightSize(keys.len))
@@ -2493,6 +2541,7 @@ proc merge*[A](s, t: CountTableRef[A]) =
       b = newCountTable("bcc")
     a.merge(b)
     doAssert a == newCountTable("aaabbbccc")
+
   s[].merge(t[])
 
 proc `$`*[A](t: CountTableRef[A]): string =
@@ -2551,6 +2600,7 @@ iterator mpairs*[A](t: CountTableRef[A]): (A, var int) =
     for k, v in mpairs(a):
       v = 2
     doAssert a == newCountTable("aabbccddrr")
+
   for h in 0..high(t.data):
     if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
 
@@ -2565,6 +2615,7 @@ iterator keys*[A](t: CountTableRef[A]): A =
     for k in keys(a):
       a[k] = 2
     doAssert a == newCountTable("aabbccddrr")
+
   for h in 0..high(t.data):
     if t.data[h].val != 0: yield t.data[h].key
 
@@ -2579,6 +2630,7 @@ iterator values*[A](t: CountTableRef[A]): int =
     let a = newCountTable("abracadabra")
     for v in values(a):
       assert v < 10
+
   for h in 0..high(t.data):
     if t.data[h].val != 0: yield t.data[h].val
 
@@ -2593,6 +2645,7 @@ iterator mvalues*[A](t: CountTableRef[A]): var int =
     for v in mvalues(a):
       v = 2
     doAssert a == newCountTable("aabbccddrr")
+
   for h in 0..high(t.data):
     if t.data[h].val != 0: yield t.data[h].val
 
@@ -2813,3 +2866,99 @@ when isMainModule:
     doAssert "test1" == orf.getOrDefault("test1", "test1")
     orf["test2"] = "test2"
     doAssert "test2" == orf.getOrDefault("test2", "test1")
+
+  block tableWithoutInit:
+    var
+      a: Table[string, int]
+      b: Table[string, int]
+      c: Table[string, int]
+      d: Table[string, int]
+      e: Table[string, int]
+
+    a["a"] = 7
+    doAssert a.hasKey("a")
+    doAssert a.len == 1
+    doAssert a["a"] == 7
+    a["a"] = 9
+    doAssert a.len == 1
+    doAssert a["a"] == 9
+
+    doAssert b.hasKeyOrPut("b", 5) == false
+    doAssert b.hasKey("b")
+    doAssert b.hasKeyOrPut("b", 8)
+    doAssert b["b"] == 5
+
+    doAssert c.getOrDefault("a") == 0
+    doAssert c.getOrDefault("a", 3) == 3
+    c["a"] = 6
+    doAssert c.getOrDefault("a", 3) == 6
+
+    doAssert d.mgetOrPut("a", 3) == 3
+    doAssert d.mgetOrPut("a", 6) == 3
+
+    var x = 99
+    doAssert e.take("a", x) == false
+    doAssert x == 99
+    e["a"] = 77
+    doAssert e.take("a", x)
+    doAssert x == 77
+
+  block orderedTableWithoutInit:
+    var
+      a: OrderedTable[string, int]
+      b: OrderedTable[string, int]
+      c: OrderedTable[string, int]
+      d: OrderedTable[string, int]
+
+    a["a"] = 7
+    doAssert a.hasKey("a")
+    doAssert a.len == 1
+    doAssert a["a"] == 7
+    a["a"] = 9
+    doAssert a.len == 1
+    doAssert a["a"] == 9
+
+    doAssert b.hasKeyOrPut("b", 5) == false
+    doAssert b.hasKey("b")
+    doAssert b.hasKeyOrPut("b", 8)
+    doAssert b["b"] == 5
+
+    doAssert c.getOrDefault("a") == 0
+    doAssert c.getOrDefault("a", 3) == 3
+    c["a"] = 6
+    doAssert c.getOrDefault("a", 3) == 6
+
+    doAssert d.mgetOrPut("a", 3) == 3
+    doAssert d.mgetOrPut("a", 6) == 3
+
+  block countTableWithoutInit:
+    var
+      a: CountTable[string]
+      b: CountTable[string]
+      c: CountTable[string]
+      d: CountTable[string]
+      e: CountTable[string]
+
+    a["a"] = 7
+    doAssert a.hasKey("a")
+    doAssert a.len == 1
+    doAssert a["a"] == 7
+    a["a"] = 9
+    doAssert a.len == 1
+    doAssert a["a"] == 9
+
+    doAssert b["b"] == 0
+    b.inc("b")
+    doAssert b["b"] == 1
+
+    doAssert c.getOrDefault("a") == 0
+    doAssert c.getOrDefault("a", 3) == 3
+    c["a"] = 6
+    doAssert c.getOrDefault("a", 3) == 6
+
+    e["f"] = 3
+    merge(d, e)
+    doAssert d.hasKey("f")
+    d.inc("f")
+    merge(d, e)
+    doAssert d["f"] == 7
diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim
index 97bc51bc5..ff12be90f 100644
--- a/lib/pure/dynlib.nim
+++ b/lib/pure/dynlib.nim
@@ -12,10 +12,10 @@
 ## Windows ``LoadLibrary``.
 ##
 ## Examples
-## --------
+## ========
 ##
 ## Loading a simple C function
-## ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+## ---------------------------
 ##
 ## The following example demonstrates loading a function called 'greet'
 ## from a library that is determined at runtime based upon a language choice.
diff --git a/lib/pure/htmlgen.nim b/lib/pure/htmlgen.nim
index fca78fb0f..fd6432bae 100644
--- a/lib/pure/htmlgen.nim
+++ b/lib/pure/htmlgen.nim
@@ -16,7 +16,8 @@
 ## generator. Each commonly used HTML tag has a corresponding macro
 ## that generates a string with its HTML representation.
 ##
-## Example:
+## Examples
+## ========
 ##
 ## .. code-block:: Nim
 ##   var nim = "Nim"
diff --git a/lib/pure/includes/osenv.nim b/lib/pure/includes/osenv.nim
index f9c076158..bc4750121 100644
--- a/lib/pure/includes/osenv.nim
+++ b/lib/pure/includes/osenv.nim
@@ -1,6 +1,6 @@
 # Include file that implements 'getEnv' and friends. Do not import it!
 
-when not declared(os):
+when not declared(os) and not declared(ospaths):
   {.error: "This is an include file for os.nim!".}
 
 from parseutils import skipIgnoreCase
diff --git a/lib/pure/includes/oserr.nim b/lib/pure/includes/oserr.nim
index 947bdd9a9..68ce5d95f 100644
--- a/lib/pure/includes/oserr.nim
+++ b/lib/pure/includes/oserr.nim
@@ -1,6 +1,6 @@
 # Include file that implements 'osErrorMsg' and friends. Do not import it!
 
-when not declared(os):
+when not declared(os) and not declared(ospaths):
   {.error: "This is an include file for os.nim!".}
 
 when not defined(nimscript):
diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim
index d043cd321..d85359953 100644
--- a/lib/pure/parsecfg.nim
+++ b/lib/pure/parsecfg.nim
@@ -12,48 +12,46 @@
 ## format, but much more powerful, as it is not a line based parser. String
 ## literals, raw string literals and triple quoted string literals are supported
 ## as in the Nim programming language.
-
-## This is an example of how a configuration file may look like:
+##
+## Example of how a configuration file may look like:
 ##
 ## .. include:: ../../doc/mytest.cfg
 ##     :literal:
 ##
-
-##[ Here is an example of how to use the configuration file parser:
-
-.. code-block:: nim
-
-    import
-      os, parsecfg, strutils, streams
-
-    var f = newFileStream(paramStr(1), fmRead)
-    if f != nil:
-      var p: CfgParser
-      open(p, f, paramStr(1))
-      while true:
-        var e = next(p)
-        case e.kind
-        of cfgEof: break
-        of cfgSectionStart:   ## a ``[section]`` has been parsed
-          echo("new section: " & e.section)
-        of cfgKeyValuePair:
-          echo("key-value-pair: " & e.key & ": " & e.value)
-        of cfgOption:
-          echo("command: " & e.key & ": " & e.value)
-        of cfgError:
-          echo(e.msg)
-      close(p)
-    else:
-      echo("cannot open: " & paramStr(1))
-
-]##
-
+## Here is an example of how to use the configuration file parser:
+##
+## .. code-block:: nim
+##
+##    import os, parsecfg, strutils, streams
+##
+##    var f = newFileStream(paramStr(1), fmRead)
+##    if f != nil:
+##      var p: CfgParser
+##      open(p, f, paramStr(1))
+##      while true:
+##        var e = next(p)
+##        case e.kind
+##        of cfgEof: break
+##        of cfgSectionStart:   ## a ``[section]`` has been parsed
+##          echo("new section: " & e.section)
+##        of cfgKeyValuePair:
+##          echo("key-value-pair: " & e.key & ": " & e.value)
+##        of cfgOption:
+##          echo("command: " & e.key & ": " & e.value)
+##        of cfgError:
+##          echo(e.msg)
+##      close(p)
+##    else:
+##      echo("cannot open: " & paramStr(1))
+##
+##
 ## Examples
-## --------
+## ========
 ##
-## This is an example of a configuration file.
+## Configuration file example
+## --------------------------
 ##
-## ::
+## .. code-block:: nim
 ##
 ##     charset = "utf-8"
 ##     [Package]
@@ -64,8 +62,8 @@
 ##     qq = "10214028"
 ##     email = "lihaifeng@wxm.com"
 ##
-## Creating a configuration file.
-## ==============================
+## Creating a configuration file
+## -----------------------------
 ## .. code-block:: nim
 ##
 ##     import parsecfg
@@ -78,8 +76,8 @@
 ##     dict.setSectionKey("Author","email","lihaifeng@wxm.com")
 ##     dict.writeConfig("config.ini")
 ##
-## Reading a configuration file.
-## =============================
+## Reading a configuration file
+## ----------------------------
 ## .. code-block:: nim
 ##
 ##     import parsecfg
@@ -92,8 +90,8 @@
 ##     var email = dict.getSectionValue("Author","email")
 ##     echo pname & "\n" & name & "\n" & qq & "\n" & email
 ##
-## Modifying a configuration file.
-## ===============================
+## Modifying a configuration file
+## ------------------------------
 ## .. code-block:: nim
 ##
 ##     import parsecfg
@@ -101,8 +99,8 @@
 ##     dict.setSectionKey("Author","name","lhf")
 ##     dict.writeConfig("config.ini")
 ##
-## Deleting a section key in a configuration file.
-## ===============================================
+## Deleting a section key in a configuration file
+## ----------------------------------------------
 ## .. code-block:: nim
 ##
 ##     import parsecfg
@@ -443,17 +441,17 @@ proc next*(c: var CfgParser): CfgEvent {.rtl, extern: "npc$1".} =
 
 # ---------------- Configuration file related operations ----------------
 type
-  Config* = OrderedTableRef[string, OrderedTableRef[string, string]]
+  Config* = OrderedTableRef[string, <//>OrderedTableRef[string, string]]
 
 proc newConfig*(): Config =
   ## Create a new configuration table.
   ## Useful when wanting to create a configuration file.
-  result = newOrderedTable[string, OrderedTableRef[string, string]]()
+  result = newOrderedTable[string, <//>OrderedTableRef[string, string]]()
 
-proc loadConfig*(stream: Stream, filename: string = "[stream]"): Config =
+proc loadConfig*(stream: Stream, filename: string = "[stream]"): <//>Config =
   ## Load the specified configuration from stream into a new Config instance.
   ## `filename` parameter is only used for nicer error messages.
-  var dict = newOrderedTable[string, OrderedTableRef[string, string]]()
+  var dict = newOrderedTable[string, <//>OrderedTableRef[string, string]]()
   var curSection = "" ## Current section,
                       ## the default value of the current section is "",
                       ## which means that the current section is a common
@@ -483,7 +481,7 @@ proc loadConfig*(stream: Stream, filename: string = "[stream]"): Config =
   close(p)
   result = dict
 
-proc loadConfig*(filename: string): Config =
+proc loadConfig*(filename: string): <//>Config =
   ## Load the specified configuration file into a new Config instance.
   let file = open(filename, fmRead)
   let fileStream = newFileStream(file)
diff --git a/lib/pure/parseutils.nim b/lib/pure/parseutils.nim
index ba09347a2..a4032f8f3 100644
--- a/lib/pure/parseutils.nim
+++ b/lib/pure/parseutils.nim
@@ -64,104 +64,154 @@ const
 proc toLower(c: char): char {.inline.} =
   result = if c in {'A'..'Z'}: chr(ord(c)-ord('A')+ord('a')) else: c
 
-proc parseHex*(s: string, number: var int, start = 0; maxLen = 0): int {.
-  rtl, extern: "npuParseHex", noSideEffect.}  =
-  ## Parses a hexadecimal number and stores its value in ``number``.
+proc parseBin*[T: SomeInteger](s: string, number: var T, start = 0, maxLen = 0): int
+  {.noSideEffect.} =
+  ## Parses a binary number and stores its value in ``number``.
   ##
-  ## Returns the number of the parsed characters or 0 in case of an error. This
-  ## proc is sensitive to the already existing value of ``number`` and will
-  ## likely not do what you want unless you make sure ``number`` is zero. You
-  ## can use this feature to *chain* calls, though the result int will quickly
-  ## overflow.
+  ## Returns the number of the parsed characters or 0 in case of an error.
+  ## If error, the value of ``number`` is not changed.
   ##
-  ## If ``maxLen == 0`` the length of the hexadecimal number has no upper bound.
-  ## Else no more than ``start + maxLen`` characters are parsed, up to the
-  ## length of the string.
+  ## If ``maxLen == 0``, the parsing continues until the first non-bin character
+  ## or to the end of the string. Otherwise, no more than ``maxLen`` characters
+  ## are parsed starting from the ``start`` position.
+  ## 
+  ## It does not check for overflow. If the value represented by the string is
+  ## too big to fit into ``number``, only the value of last fitting characters
+  ## will be stored in ``number`` without producing an error.
   runnableExamples:
-    var value = 0
-    discard parseHex("0x38", value)
-    assert value == 56
-    discard parseHex("0x34", value)
-    assert value == 56 * 256 + 52
-    value = -1
-    discard parseHex("0x38", value)
-    assert value == -200
+    var num: int
+    doAssert parseBin("0100_1110_0110_1001_1110_1101", num) == 29
+    doAssert num == 5138925
+    doAssert parseBin("3", num) == 0
+    var num8: int8
+    doAssert parseBin("0b_0100_1110_0110_1001_1110_1101", num8) == 32
+    doAssert num8 == 0b1110_1101'i8
+    doAssert parseBin("0b_0100_1110_0110_1001_1110_1101", num8, 3, 9) == 9
+    doAssert num8 == 0b0100_1110'i8
+    var num8u: uint8
+    doAssert parseBin("0b_0100_1110_0110_1001_1110_1101", num8u) == 32
+    doAssert num8u == 237
+    var num64: int64
+    doAssert parseBin("0100111001101001111011010100111001101001", num64) == 40
+    doAssert num64 == 336784608873
   var i = start
+  var output = T(0)
   var foundDigit = false
-  # get last index based on minimum `start + maxLen` or `s.len`
-  let last = min(s.len, if maxLen == 0: s.len else: i+maxLen)
-  if i+1 < last and s[i] == '0' and (s[i+1] in {'x', 'X'}): inc(i, 2)
-  elif i < last and s[i] == '#': inc(i)
+  let last = min(s.len, if maxLen == 0: s.len else: i + maxLen)
+  if i + 1 < last and s[i] == '0' and (s[i+1] in {'b', 'B'}): inc(i, 2)
   while i < last:
     case s[i]
     of '_': discard
-    of '0'..'9':
-      number = number shl 4 or (ord(s[i]) - ord('0'))
-      foundDigit = true
-    of 'a'..'f':
-      number = number shl 4 or (ord(s[i]) - ord('a') + 10)
-      foundDigit = true
-    of 'A'..'F':
-      number = number shl 4 or (ord(s[i]) - ord('A') + 10)
+    of '0'..'1':
+      output = output shl 1 or T(ord(s[i]) - ord('0'))
       foundDigit = true
     else: break
     inc(i)
-  if foundDigit: result = i-start
+  if foundDigit:
+    number = output
+    result = i - start
 
-proc parseOct*(s: string, number: var int, start = 0, maxLen = 0): int  {.
-  rtl, extern: "npuParseOct", noSideEffect.} =
-  ## Parses an octal number and stores its value in ``number``. Returns
-  ## the number of the parsed characters or 0 in case of an error.
+proc parseOct*[T: SomeInteger](s: string, number: var T, start = 0, maxLen = 0): int
+  {.noSideEffect.} =
+  ## Parses an octal number and stores its value in ``number``.
+  ##
+  ## Returns the number of the parsed characters or 0 in case of an error.
+  ## If error, the value of ``number`` is not changed.
   ##
-  ## If ``maxLen == 0`` the length of the octal number has no upper bound.
-  ## Else no more than ``start + maxLen`` characters are parsed, up to the
-  ## length of the string.
+  ## If ``maxLen == 0``, the parsing continues until the first non-oct character
+  ## or to the end of the string. Otherwise, no more than ``maxLen`` characters
+  ## are parsed starting from the ``start`` position.
+  ## 
+  ## It does not check for overflow. If the value represented by the string is
+  ## too big to fit into ``number``, only the value of last fitting characters
+  ## will be stored in ``number`` without producing an error.
   runnableExamples:
-    var res: int
-    doAssert parseOct("12", res) == 2
-    doAssert res == 10
-    doAssert parseOct("9", res) == 0
+    var num: int
+    doAssert parseOct("0o23464755", num) == 10
+    doAssert num == 5138925
+    doAssert parseOct("8", num) == 0
+    var num8: int8
+    doAssert parseOct("0o_1464_755", num8) == 11
+    doAssert num8 == -19
+    doAssert parseOct("0o_1464_755", num8, 3, 3) == 3
+    doAssert num8 == 102
+    var num8u: uint8
+    doAssert parseOct("1464755", num8u) == 7
+    doAssert num8u == 237
+    var num64: int64
+    doAssert parseOct("2346475523464755", num64) == 16
+    doAssert num64 == 86216859871725
   var i = start
+  var output = T(0)
   var foundDigit = false
-  # get last index based on minimum `start + maxLen` or `s.len`
-  let last = min(s.len, if maxLen == 0: s.len else: i+maxLen)
-  if i+1 < last and s[i] == '0' and (s[i+1] in {'o', 'O'}): inc(i, 2)
+  let last = min(s.len, if maxLen == 0: s.len else: i + maxLen)
+  if i + 1 < last and s[i] == '0' and (s[i+1] in {'o', 'O'}): inc(i, 2)
   while i < last:
     case s[i]
     of '_': discard
     of '0'..'7':
-      number = number shl 3 or (ord(s[i]) - ord('0'))
+      output = output shl 3 or T(ord(s[i]) - ord('0'))
       foundDigit = true
     else: break
     inc(i)
-  if foundDigit: result = i-start
+  if foundDigit:
+    number = output
+    result = i - start
 
-proc parseBin*(s: string, number: var int, start = 0, maxLen = 0): int {.
-  rtl, extern: "npuParseBin", noSideEffect.} =
-  ## Parses an binary number and stores its value in ``number``. Returns
-  ## the number of the parsed characters or 0 in case of an error.
+proc parseHex*[T: SomeInteger](s: string, number: var T, start = 0, maxLen = 0): int
+  {.noSideEffect.} =
+  ## Parses a hexadecimal number and stores its value in ``number``.
+  ##
+  ## Returns the number of the parsed characters or 0 in case of an error.
+  ## If error, the value of ``number`` is not changed.
   ##
-  ## If ``maxLen == 0`` the length of the binary number has no upper bound.
-  ## Else no more than ``start + maxLen`` characters are parsed, up to the
-  ## length of the string.
+  ## If ``maxLen == 0``, the parsing continues until the first non-hex character
+  ## or to the end of the string. Otherwise, no more than ``maxLen`` characters
+  ## are parsed starting from the ``start`` position.
+  ## 
+  ## It does not check for overflow. If the value represented by the string is
+  ## too big to fit into ``number``, only the value of last fitting characters
+  ## will be stored in ``number`` without producing an error.
   runnableExamples:
-    var res: int
-    doAssert parseBin("010011100110100101101101", res) == 24
-    doAssert parseBin("3", res) == 0
+    var num: int
+    doAssert parseHex("4E_69_ED", num) == 8
+    doAssert num == 5138925
+    doAssert parseHex("X", num) == 0
+    doAssert parseHex("#ABC", num) == 4
+    var num8: int8
+    doAssert parseHex("0x_4E_69_ED", num8) == 11
+    doAssert num8 == 0xED'i8
+    doAssert parseHex("0x_4E_69_ED", num8, 3, 2) == 2
+    doAssert num8 == 0x4E'i8
+    var num8u: uint8
+    doAssert parseHex("0x_4E_69_ED", num8u) == 11
+    doAssert num8u == 237
+    var num64: int64
+    doAssert parseHex("4E69ED4E69ED", num64) == 12
+    doAssert num64 == 86216859871725
   var i = start
+  var output = T(0)
   var foundDigit = false
-  # get last index based on minimum `start + maxLen` or `s.len`
-  let last = min(s.len, if maxLen == 0: s.len else: i+maxLen)
-  if i+1 < last and s[i] == '0' and (s[i+1] in {'b', 'B'}): inc(i, 2)
+  let last = min(s.len, if maxLen == 0: s.len else: i + maxLen)
+  if i + 1 < last and s[i] == '0' and (s[i+1] in {'x', 'X'}): inc(i, 2)
+  elif i < last and s[i] == '#': inc(i)
   while i < last:
     case s[i]
     of '_': discard
-    of '0'..'1':
-      number = number shl 1 or (ord(s[i]) - ord('0'))
+    of '0'..'9':
+      output = output shl 4 or T(ord(s[i]) - ord('0'))
+      foundDigit = true
+    of 'a'..'f':
+      output = output shl 4 or T(ord(s[i]) - ord('a') + 10)
+      foundDigit = true
+    of 'A'..'F':
+      output = output shl 4 or T(ord(s[i]) - ord('A') + 10)
       foundDigit = true
     else: break
     inc(i)
-  if foundDigit: result = i-start
+  if foundDigit:
+    number = output
+    result = i - start
 
 proc parseIdent*(s: string, ident: var string, start = 0): int =
   ## Parses an identifier and stores it in ``ident``. Returns
@@ -605,11 +655,6 @@ when isMainModule:
   var value = 0
   discard parseHex("0x38", value)
   doAssert value == 56
-  discard parseHex("0x34", value)
-  doAssert value == 56 * 256 + 52
-  value = -1
-  discard parseHex("0x38", value)
-  doAssert value == -200
 
   value = -1
   doAssert(parseSaturatedNatural("848", value) == 3)
diff --git a/lib/pure/random.nim b/lib/pure/random.nim
index e29ad7955..dddbd9d58 100644
--- a/lib/pure/random.nim
+++ b/lib/pure/random.nim
@@ -129,7 +129,7 @@ proc next*(r: var Rand): uint64 =
   ##   a given upper bound
   ## * `rand proc<#rand,Rand,range[]>`_ that returns a float
   ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ that accepts a slice
-  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer type
+  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type
   ## * `skipRandomNumbers proc<#skipRandomNumbers,Rand>`_
   runnableExamples:
     var r = initRand(2019)
@@ -242,7 +242,7 @@ proc rand*(r: var Rand; max: Natural): int {.benign.} =
   ##   random number generator
   ## * `rand proc<#rand,Rand,range[]>`_ that returns a float
   ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ that accepts a slice
-  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer type
+  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type
   runnableExamples:
     var r = initRand(123)
     doAssert r.rand(100) == 0
@@ -268,7 +268,7 @@ proc rand*(max: int): int {.benign.} =
   ##   provided state
   ## * `rand proc<#rand,float>`_ that returns a float
   ## * `rand proc<#rand,HSlice[T,T]>`_ that accepts a slice
-  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer type
+  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type
   runnableExamples:
     randomize(123)
     doAssert rand(100) == 0
@@ -285,7 +285,7 @@ proc rand*(r: var Rand; max: range[0.0 .. high(float)]): float {.benign.} =
   ##   random number generator
   ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer
   ## * `rand proc<#rand,Rand,HSlice[T,T]>`_ that accepts a slice
-  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer type
+  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type
   runnableExamples:
     var r = initRand(234)
     let f = r.rand(1.0)
@@ -311,7 +311,7 @@ proc rand*(max: float): float {.benign.} =
   ##   provided state
   ## * `rand proc<#rand,int>`_ that returns an integer
   ## * `rand proc<#rand,HSlice[T,T]>`_ that accepts a slice
-  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer type
+  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type
   runnableExamples:
     randomize(234)
     let f = rand(1.0)
@@ -327,7 +327,7 @@ proc rand*[T: Ordinal](r: var Rand; x: HSlice[T, T]): T =
   ##   default random number generator
   ## * `rand proc<#rand,Rand,Natural>`_ that returns an integer
   ## * `rand proc<#rand,Rand,range[]>`_ that returns a float
-  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer type
+  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type
   runnableExamples:
     var r = initRand(345)
     doAssert r.rand(1..6) == 4
@@ -349,7 +349,7 @@ proc rand*[T: Ordinal](x: HSlice[T, T]): T =
   ##   a provided state
   ## * `rand proc<#rand,int>`_ that returns an integer
   ## * `rand proc<#rand,float>`_ that returns a floating point number
-  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer type
+  ## * `rand proc<#rand,typedesc[T]>`_ that accepts an integer or range type
   runnableExamples:
     randomize(345)
     doAssert rand(1..6) == 4
@@ -383,7 +383,13 @@ proc rand*[T: SomeInteger](t: typedesc[T]): T =
     doAssert rand(uint32) == 578980729'u32
     doAssert rand(uint32) == 4052940463'u32
     doAssert rand(uint32) == 2163872389'u32
-  result = cast[T](state.next)
+    doAssert rand(range[1..16]) == 11
+    doAssert rand(range[1..16]) == 4
+    doAssert rand(range[1..16]) == 16
+  when T is range:
+    result = rand(state, low(T)..high(T))
+  else:
+    result = cast[T](state.next)
 
 proc rand*[T](a: openArray[T]): T {.deprecated.} =
   ## **Deprecated since version 0.20.0:**
diff --git a/lib/pure/streams.nim b/lib/pure/streams.nim
index ff2b72725..83c8c71ec 100644
--- a/lib/pure/streams.nim
+++ b/lib/pure/streams.nim
@@ -8,29 +8,91 @@
 #
 
 ## This module provides a stream interface and two implementations thereof:
-## the `FileStream` and the `StringStream` which implement the stream
-## interface for Nim file objects (`File`) and strings. Other modules
-## may provide other implementations for this standard stream interface.
+## the `FileStream <#FileStream>`_ and the `StringStream <#StringStream>`_
+## which implement the stream interface for Nim file objects (`File`) and
+## strings.
 ##
-## Examples:
+## Other modules may provide other implementations for this standard
+## stream interface.
+##
+## Basic usage
+## ===========
+##
+## The basic flow of using this module is:
+##
+## 1. Open input stream
+## 2. Read or write stream
+## 3. Close stream
+##
+## StringStream example
+## --------------------
 ##
 ## .. code-block:: Nim
 ##
 ##  import streams
-##  var
-##    ss = newStringStream("""The first line
+##
+##  var strm = newStringStream("""The first line
 ##  the second line
 ##  the third line""")
-##    line = ""
-##  while ss.readLine(line):
+##
+##  var line = ""
+##
+##  while strm.readLine(line):
 ##    echo line
-##  ss.close()
 ##
-##  var fs = newFileStream("somefile.txt", fmRead)
-##  if not isNil(fs):
-##    while fs.readLine(line):
+##  # Output:
+##  # The first line
+##  # the second line
+##  # the third line
+##
+##  strm.close()
+##
+## FileStream example
+## ------------------
+##
+## Write file stream example:
+##
+## .. code-block:: Nim
+##
+##  import streams
+##
+##  var strm = newFileStream("somefile.txt", fmWrite)
+##  var line = ""
+##
+##  if not isNil(strm):
+##    strm.writeLine("The first line")
+##    strm.writeLine("the second line")
+##    strm.writeLine("the third line")
+##    strm.close()
+##
+##  # Output (somefile.txt):
+##  # The first line
+##  # the second line
+##  # the third line
+##
+## Read file stream example:
+##
+## .. code-block:: Nim
+##
+##  import streams
+##
+##  var strm = newFileStream("somefile.txt", fmRead)
+##  var line = ""
+##
+##  if not isNil(strm):
+##    while strm.readLine(line):
 ##      echo line
-##    fs.close()
+##    strm.close()
+##
+##  # Output:
+##  # The first line
+##  # the second line
+##  # the third line
+##
+## See also
+## ========
+## * `asyncstreams module <asyncstreams.html>`_
+## * `io module <io.html>`_ for `FileMode enum <io.html#FileMode>`_
 
 include "system/inclrtl"
 
@@ -40,11 +102,14 @@ proc newEIO(msg: string): owned(ref IOError) =
 
 type
   Stream* = ref StreamObj
-  StreamObj* = object of RootObj ## Stream interface that supports
-                                 ## writing or reading. Note that these fields
-                                 ## here shouldn't be used directly. They are
-                                 ## accessible so that a stream implementation
-                                 ## can override them.
+    ## All procedures of this module use this type.
+    ## Procedures don't directly use `StreamObj <#StreamObj>`_.
+  StreamObj* = object of RootObj
+    ## Stream interface that supports writing or reading.
+    ##
+    ## **Note:**
+    ## * That these fields here shouldn't be used directly.
+    ##   They are accessible so that a stream implementation can override them.
     closeImpl*: proc (s: Stream)
       {.nimcall, raises: [Exception, IOError, OSError], tags: [WriteIOEffect], gcsafe.}
     atEndImpl*: proc (s: Stream): bool
@@ -68,32 +133,103 @@ type
       {.nimcall, raises: [Defect, IOError, OSError], tags: [WriteIOEffect], gcsafe.}
 
 proc flush*(s: Stream) =
-  ## flushes the buffers that the stream `s` might use.
+  ## Flushes the buffers that the stream `s` might use.
+  ##
+  ## This procedure causes any unwritten data for that stream to be delivered
+  ## to the host environment to be written to the file.
+  ##
+  ## See also:
+  ## * `close proc <#close,Stream>`_
+  runnableExamples:
+    from os import removeFile
+
+    var strm = newFileStream("somefile.txt", fmWrite)
+
+    doAssert "Before write:" & readFile("somefile.txt") == "Before write:"
+    strm.write("hello")
+    doAssert "After  write:" & readFile("somefile.txt") == "After  write:"
+
+    strm.flush()
+    doAssert "After  flush:" & readFile("somefile.txt") == "After  flush:hello"
+    strm.write("HELLO")
+    strm.flush()
+    doAssert "After  flush:" & readFile("somefile.txt") == "After  flush:helloHELLO"
+
+    strm.close()
+    doAssert "After  close:" & readFile("somefile.txt") == "After  close:helloHELLO"
+    removeFile("somefile.txt")
+
   if not isNil(s.flushImpl): s.flushImpl(s)
 
 proc close*(s: Stream) =
-  ## closes the stream `s`.
+  ## Closes the stream `s`.
+  ##
+  ## See also:
+  ## * `flush proc <#flush,Stream>`_
+  runnableExamples:
+    var strm = newStringStream("The first line\nthe second line\nthe third line")
+    ## do something...
+    strm.close()
   if not isNil(s.closeImpl): s.closeImpl(s)
 
 proc atEnd*(s: Stream): bool =
-  ## checks if more data can be read from `f`. Returns true if all data has
+  ## Checks if more data can be read from `s`. Returns ``true`` if all data has
   ## been read.
+  runnableExamples:
+    var strm = newStringStream("The first line\nthe second line\nthe third line")
+    var line = ""
+    doAssert strm.atEnd() == false
+    while strm.readLine(line):
+      discard
+    doAssert strm.atEnd() == true
+    strm.close()
+
   result = s.atEndImpl(s)
 
 proc setPosition*(s: Stream, pos: int) =
-  ## sets the position `pos` of the stream `s`.
+  ## Sets the position `pos` of the stream `s`.
+  runnableExamples:
+    var strm = newStringStream("The first line\nthe second line\nthe third line")
+    strm.setPosition(4)
+    doAssert strm.readLine() == "first line"
+    strm.setPosition(0)
+    doAssert strm.readLine() == "The first line"
+    strm.close()
+
   s.setPositionImpl(s, pos)
 
 proc getPosition*(s: Stream): int =
-  ## retrieves the current position in the stream `s`.
+  ## Retrieves the current position in the stream `s`.
+  runnableExamples:
+    var strm = newStringStream("The first line\nthe second line\nthe third line")
+    doAssert strm.getPosition() == 0
+    discard strm.readLine()
+    doAssert strm.getPosition() == 15
+    strm.close()
+
   result = s.getPositionImpl(s)
 
 proc readData*(s: Stream, buffer: pointer, bufLen: int): int =
-  ## low level proc that reads data into an untyped `buffer` of `bufLen` size.
+  ## Low level proc that reads data into an untyped `buffer` of `bufLen` size.
+  runnableExamples:
+    var strm = newStringStream("abcde")
+    var buffer: array[6, char]
+    doAssert strm.readData(addr(buffer), 1024) == 5
+    doAssert buffer == ['a', 'b', 'c', 'd', 'e', '\x00']
+    doAssert strm.atEnd() == true
+    strm.close()
+
   result = s.readDataImpl(s, buffer, bufLen)
 
 proc readDataStr*(s: Stream, buffer: var string, slice: Slice[int]): int =
-  ## low level proc that reads data into a string ``buffer`` at ``slice``.
+  ## Low level proc that reads data into a string ``buffer`` at ``slice``.
+  runnableExamples:
+    var strm = newStringStream("abcde")
+    var buffer = "12345"
+    doAssert strm.readDataStr(buffer, 0..3) == 4
+    doAssert buffer == "abcd5"
+    strm.close()
+
   if s.readDataStrImpl != nil:
     result = s.readDataStrImpl(s, buffer, slice)
   else:
@@ -103,6 +239,14 @@ proc readDataStr*(s: Stream, buffer: var string, slice: Slice[int]): int =
 when not defined(js):
   proc readAll*(s: Stream): string =
     ## Reads all available data.
+    ##
+    ## **Note:** Not available for JS backend.
+    runnableExamples:
+      var strm = newStringStream("The first line\nthe second line\nthe third line")
+      doAssert strm.readAll() == "The first line\nthe second line\nthe third line"
+      doAssert strm.atEnd() == true
+      strm.close()
+
     const bufferSize = 1024
     var buffer {.noinit.}: array[bufferSize, char]
     while true:
@@ -116,173 +260,611 @@ when not defined(js):
         break
 
 proc peekData*(s: Stream, buffer: pointer, bufLen: int): int =
-  ## low level proc that reads data into an untyped `buffer` of `bufLen` size
-  ## without moving stream position
+  ## Low level proc that reads data into an untyped `buffer` of `bufLen` size
+  ## without moving stream position.
+  runnableExamples:
+    var strm = newStringStream("abcde")
+    var buffer: array[6, char]
+    doAssert strm.peekData(addr(buffer), 1024) == 5
+    doAssert buffer == ['a', 'b', 'c', 'd', 'e', '\x00']
+    doAssert strm.atEnd() == false
+    strm.close()
+
   result = s.peekDataImpl(s, buffer, bufLen)
 
 proc writeData*(s: Stream, buffer: pointer, bufLen: int) =
-  ## low level proc that writes an untyped `buffer` of `bufLen` size
+  ## Low level proc that writes an untyped `buffer` of `bufLen` size
   ## to the stream `s`.
+  runnableExamples:
+    ## writeData
+    var strm = newStringStream("")
+    var buffer = ['a', 'b', 'c', 'd', 'e']
+    strm.writeData(addr(buffer), sizeof(buffer))
+    doAssert strm.atEnd() == true
+    ## readData
+    strm.setPosition(0)
+    var buffer2: array[6, char]
+    doAssert strm.readData(addr(buffer2), sizeof(buffer2)) == 5
+    doAssert buffer2 == ['a', 'b', 'c', 'd', 'e', '\x00']
+    strm.close()
+
   s.writeDataImpl(s, buffer, bufLen)
 
 proc write*[T](s: Stream, x: T) =
-  ## generic write procedure. Writes `x` to the stream `s`. Implementation:
+  ## Generic write procedure. Writes `x` to the stream `s`. Implementation:
   ##
   ## .. code-block:: Nim
   ##
   ##     s.writeData(s, addr(x), sizeof(x))
+  runnableExamples:
+    var strm = newStringStream("")
+    strm.write("abcde")
+    strm.setPosition(0)
+    doAssert strm.readAll() == "abcde"
+    strm.close()
+
   var y: T
   shallowCopy(y, x)
   writeData(s, addr(y), sizeof(y))
 
 proc write*(s: Stream, x: string) =
-  ## writes the string `x` to the the stream `s`. No length field or
+  ## Writes the string `x` to the the stream `s`. No length field or
   ## terminating zero is written.
+  runnableExamples:
+    var strm = newStringStream("")
+    strm.write("THE FIRST LINE")
+    strm.setPosition(0)
+    doAssert strm.readLine() == "THE FIRST LINE"
+    strm.close()
+
   when nimvm:
     writeData(s, cstring(x), x.len)
   else:
     if x.len > 0: writeData(s, cstring(x), x.len)
 
 proc write*(s: Stream, args: varargs[string, `$`]) =
-  ## writes one or more strings to the the stream. No length fields or
+  ## Writes one or more strings to the the stream. No length fields or
   ## terminating zeros are written.
+  runnableExamples:
+    var strm = newStringStream("")
+    strm.write(1, 2, 3, 4)
+    strm.setPosition(0)
+    doAssert strm.readLine() == "1234"
+    strm.close()
+
   for str in args: write(s, str)
 
 proc writeLine*(s: Stream, args: varargs[string, `$`]) =
-  ## writes one or more strings to the the stream `s` followed
+  ## Writes one or more strings to the the stream `s` followed
   ## by a new line. No length field or terminating zero is written.
+  runnableExamples:
+    var strm = newStringStream("")
+    strm.writeLine(1, 2)
+    strm.writeLine(3, 4)
+    strm.setPosition(0)
+    doAssert strm.readAll() == "12\n34\n"
+    strm.close()
+
   for str in args: write(s, str)
   write(s, "\n")
 
 proc read*[T](s: Stream, result: var T) =
-  ## generic read procedure. Reads `result` from the stream `s`.
+  ## Generic read procedure. Reads `result` from the stream `s`.
+  runnableExamples:
+    var strm = newStringStream("012")
+    ## readInt
+    var i: int8
+    strm.read(i)
+    doAssert i == 48
+    ## readData
+    var buffer: array[2, char]
+    strm.read(buffer)
+    doAssert buffer == ['1', '2']
+    strm.close()
+
   if readData(s, addr(result), sizeof(T)) != sizeof(T):
     raise newEIO("cannot read from stream")
 
 proc peek*[T](s: Stream, result: var T) =
-  ## generic peek procedure. Peeks `result` from the stream `s`.
+  ## Generic peek procedure. Peeks `result` from the stream `s`.
+  runnableExamples:
+    var strm = newStringStream("012")
+    ## peekInt
+    var i: int8
+    strm.peek(i)
+    doAssert i == 48
+    ## peekData
+    var buffer: array[2, char]
+    strm.peek(buffer)
+    doAssert buffer == ['0', '1']
+    strm.close()
+
   if peekData(s, addr(result), sizeof(T)) != sizeof(T):
     raise newEIO("cannot read from stream")
 
 proc readChar*(s: Stream): char =
-  ## reads a char from the stream `s`. Raises `IOError` if an error occurred.
+  ## Reads a char from the stream `s`.
+  ##
+  ## Raises `IOError` if an error occurred.
   ## Returns '\\0' as an EOF marker.
+  runnableExamples:
+    var strm = newStringStream("12\n3")
+    doAssert strm.readChar() == '1'
+    doAssert strm.readChar() == '2'
+    doAssert strm.readChar() == '\n'
+    doAssert strm.readChar() == '3'
+    doAssert strm.readChar() == '\x00'
+    strm.close()
+
   if readData(s, addr(result), sizeof(result)) != 1: result = '\0'
 
 proc peekChar*(s: Stream): char =
-  ## peeks a char from the stream `s`. Raises `IOError` if an error occurred.
+  ## Peeks a char from the stream `s`. Raises `IOError` if an error occurred.
   ## Returns '\\0' as an EOF marker.
+  runnableExamples:
+    var strm = newStringStream("12\n3")
+    doAssert strm.peekChar() == '1'
+    doAssert strm.peekChar() == '1'
+    discard strm.readAll()
+    doAssert strm.peekChar() == '\x00'
+    strm.close()
+
   if peekData(s, addr(result), sizeof(result)) != 1: result = '\0'
 
 proc readBool*(s: Stream): bool =
-  ## reads a bool from the stream `s`. Raises `IOError` if an error occurred.
+  ## Reads a bool from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(true)
+    strm.write(false)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.readBool() == true
+    doAssert strm.readBool() == false
+    doAssertRaises(IOError): discard strm.readBool()
+    strm.close()
+
   read(s, result)
 
 proc peekBool*(s: Stream): bool =
-  ## peeks a bool from the stream `s`. Raises `IOError` if an error occurred.
+  ## Peeks a bool from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(true)
+    strm.write(false)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.peekBool() == true
+    ## not false
+    doAssert strm.peekBool() == true
+    doAssert strm.readBool() == true
+    doAssert strm.peekBool() == false
+    strm.close()
+
   peek(s, result)
 
 proc readInt8*(s: Stream): int8 =
-  ## reads an int8 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Reads an int8 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'i8)
+    strm.write(2'i8)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.readInt8() == 1'i8
+    doAssert strm.readInt8() == 2'i8
+    doAssertRaises(IOError): discard strm.readInt8()
+    strm.close()
+
   read(s, result)
 
 proc peekInt8*(s: Stream): int8 =
-  ## peeks an int8 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Peeks an int8 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'i8)
+    strm.write(2'i8)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.peekInt8() == 1'i8
+    ## not 2'i8
+    doAssert strm.peekInt8() == 1'i8
+    doAssert strm.readInt8() == 1'i8
+    doAssert strm.peekInt8() == 2'i8
+    strm.close()
+
   peek(s, result)
 
 proc readInt16*(s: Stream): int16 =
-  ## reads an int16 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Reads an int16 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'i16)
+    strm.write(2'i16)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.readInt16() == 1'i16
+    doAssert strm.readInt16() == 2'i16
+    doAssertRaises(IOError): discard strm.readInt16()
+    strm.close()
+
   read(s, result)
 
 proc peekInt16*(s: Stream): int16 =
-  ## peeks an int16 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Peeks an int16 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'i16)
+    strm.write(2'i16)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.peekInt16() == 1'i16
+    ## not 2'i16
+    doAssert strm.peekInt16() == 1'i16
+    doAssert strm.readInt16() == 1'i16
+    doAssert strm.peekInt16() == 2'i16
+    strm.close()
+
   peek(s, result)
 
 proc readInt32*(s: Stream): int32 =
-  ## reads an int32 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Reads an int32 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'i32)
+    strm.write(2'i32)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.readInt32() == 1'i32
+    doAssert strm.readInt32() == 2'i32
+    doAssertRaises(IOError): discard strm.readInt32()
+    strm.close()
+
   read(s, result)
 
 proc peekInt32*(s: Stream): int32 =
-  ## peeks an int32 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Peeks an int32 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'i32)
+    strm.write(2'i32)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.peekInt32() == 1'i32
+    ## not 2'i32
+    doAssert strm.peekInt32() == 1'i32
+    doAssert strm.readInt32() == 1'i32
+    doAssert strm.peekInt32() == 2'i32
+    strm.close()
+
   peek(s, result)
 
 proc readInt64*(s: Stream): int64 =
-  ## reads an int64 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Reads an int64 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'i64)
+    strm.write(2'i64)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.readInt64() == 1'i64
+    doAssert strm.readInt64() == 2'i64
+    doAssertRaises(IOError): discard strm.readInt64()
+    strm.close()
+
   read(s, result)
 
 proc peekInt64*(s: Stream): int64 =
-  ## peeks an int64 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Peeks an int64 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'i64)
+    strm.write(2'i64)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.peekInt64() == 1'i64
+    ## not 2'i64
+    doAssert strm.peekInt64() == 1'i64
+    doAssert strm.readInt64() == 1'i64
+    doAssert strm.peekInt64() == 2'i64
+    strm.close()
+
   peek(s, result)
 
 proc readUint8*(s: Stream): uint8 =
-  ## reads an uint8 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Reads an uint8 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'u8)
+    strm.write(2'u8)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.readUint8() == 1'u8
+    doAssert strm.readUint8() == 2'u8
+    doAssertRaises(IOError): discard strm.readUint8()
+    strm.close()
+
   read(s, result)
 
 proc peekUint8*(s: Stream): uint8 =
-  ## peeks an uint8 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Peeks an uint8 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'u8)
+    strm.write(2'u8)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.peekUint8() == 1'u8
+    ## not 2'u8
+    doAssert strm.peekUint8() == 1'u8
+    doAssert strm.readUint8() == 1'u8
+    doAssert strm.peekUint8() == 2'u8
+    strm.close()
+
   peek(s, result)
 
 proc readUint16*(s: Stream): uint16 =
-  ## reads an uint16 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Reads an uint16 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'u16)
+    strm.write(2'u16)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.readUint16() == 1'u16
+    doAssert strm.readUint16() == 2'u16
+    doAssertRaises(IOError): discard strm.readUint16()
+    strm.close()
+
   read(s, result)
 
 proc peekUint16*(s: Stream): uint16 =
-  ## peeks an uint16 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Peeks an uint16 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'u16)
+    strm.write(2'u16)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.peekUint16() == 1'u16
+    ## not 2'u16
+    doAssert strm.peekUint16() == 1'u16
+    doAssert strm.readUint16() == 1'u16
+    doAssert strm.peekUint16() == 2'u16
+    strm.close()
+
   peek(s, result)
 
 proc readUint32*(s: Stream): uint32 =
-  ## reads an uint32 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Reads an uint32 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'u32)
+    strm.write(2'u32)
+    strm.flush()
+    strm.setPosition(0)
+
+    ## get data
+    doAssert strm.readUint32() == 1'u32
+    doAssert strm.readUint32() == 2'u32
+    doAssertRaises(IOError): discard strm.readUint32()
+    strm.close()
+
   read(s, result)
 
 proc peekUint32*(s: Stream): uint32 =
-  ## peeks an uint32 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Peeks an uint32 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'u32)
+    strm.write(2'u32)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.peekUint32() == 1'u32
+    ## not 2'u32
+    doAssert strm.peekUint32() == 1'u32
+    doAssert strm.readUint32() == 1'u32
+    doAssert strm.peekUint32() == 2'u32
+    strm.close()
+
   peek(s, result)
 
 proc readUint64*(s: Stream): uint64 =
-  ## reads an uint64 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Reads an uint64 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'u64)
+    strm.write(2'u64)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.readUint64() == 1'u64
+    doAssert strm.readUint64() == 2'u64
+    doAssertRaises(IOError): discard strm.readUint64()
+    strm.close()
+
   read(s, result)
 
 proc peekUint64*(s: Stream): uint64 =
-  ## peeks an uint64 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Peeks an uint64 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'u64)
+    strm.write(2'u64)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.peekUint64() == 1'u64
+    ## not 2'u64
+    doAssert strm.peekUint64() == 1'u64
+    doAssert strm.readUint64() == 1'u64
+    doAssert strm.peekUint64() == 2'u64
+    strm.close()
+
   peek(s, result)
 
 proc readFloat32*(s: Stream): float32 =
-  ## reads a float32 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Reads a float32 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'f32)
+    strm.write(2'f32)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.readFloat32() == 1'f32
+    doAssert strm.readFloat32() == 2'f32
+    doAssertRaises(IOError): discard strm.readFloat32()
+    strm.close()
+
   read(s, result)
 
 proc peekFloat32*(s: Stream): float32 =
-  ## peeks a float32 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Peeks a float32 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'f32)
+    strm.write(2'f32)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.peekFloat32() == 1'f32
+    ## not 2'f32
+    doAssert strm.peekFloat32() == 1'f32
+    doAssert strm.readFloat32() == 1'f32
+    doAssert strm.peekFloat32() == 2'f32
+    strm.close()
+
   peek(s, result)
 
 proc readFloat64*(s: Stream): float64 =
-  ## reads a float64 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Reads a float64 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'f64)
+    strm.write(2'f64)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.readFloat64() == 1'f64
+    doAssert strm.readFloat64() == 2'f64
+    doAssertRaises(IOError): discard strm.readFloat64()
+    strm.close()
+
   read(s, result)
 
 proc peekFloat64*(s: Stream): float64 =
-  ## peeks a float64 from the stream `s`. Raises `IOError` if an error occurred.
+  ## Peeks a float64 from the stream `s`. Raises `IOError` if an error occurred.
+  runnableExamples:
+    var strm = newStringStream()
+    ## setup for reading data
+    strm.write(1'f64)
+    strm.write(2'f64)
+    strm.flush()
+    strm.setPosition(0)
+    ## get data
+    doAssert strm.peekFloat64() == 1'f64
+    ## not 2'f64
+    doAssert strm.peekFloat64() == 1'f64
+    doAssert strm.readFloat64() == 1'f64
+    doAssert strm.peekFloat64() == 2'f64
+    strm.close()
+
   peek(s, result)
 
 proc readStr*(s: Stream, length: int): TaintedString =
-  ## reads a string of length `length` from the stream `s`. Raises `IOError` if
+  ## Reads a string of length `length` from the stream `s`. Raises `IOError` if
   ## an error occurred.
+  runnableExamples:
+    var strm = newStringStream("abcde")
+    doAssert strm.readStr(2) == "ab"
+    doAssert strm.readStr(2) == "cd"
+    doAssert strm.readStr(2) == "e"
+    doAssert strm.readStr(2) == ""
+    strm.close()
+
   result = newString(length).TaintedString
   var L = readData(s, cstring(result), length)
   if L != length: setLen(result.string, L)
 
 proc peekStr*(s: Stream, length: int): TaintedString =
-  ## peeks a string of length `length` from the stream `s`. Raises `IOError` if
+  ## Peeks a string of length `length` from the stream `s`. Raises `IOError` if
   ## an error occurred.
+  runnableExamples:
+    var strm = newStringStream("abcde")
+    doAssert strm.peekStr(2) == "ab"
+    ## not "cd
+    doAssert strm.peekStr(2) == "ab"
+    doAssert strm.readStr(2) == "ab"
+    doAssert strm.peekStr(2) == "cd"
+    strm.close()
+
   result = newString(length).TaintedString
   var L = peekData(s, cstring(result), length)
   if L != length: setLen(result.string, L)
 
 proc readLine*(s: Stream, line: var TaintedString): bool =
-  ## reads a line of text from the stream `s` into `line`. `line` must not be
+  ## Reads a line of text from the stream `s` into `line`. `line` must not be
   ## ``nil``! May throw an IO exception.
+  ##
   ## A line of text may be delimited by ``LF`` or ``CRLF``.
   ## The newline character(s) are not part of the returned string.
   ## Returns ``false`` if the end of the file has been reached, ``true``
   ## otherwise. If ``false`` is returned `line` contains no new data.
+  ##
+  ## See also:
+  ## * `readLine(Stream) proc <#readLine,Stream>`_
+  ## * `peekLine(Stream) proc <#peekLine,Stream>`_
+  ## * `peekLine(Stream, TaintedString) proc <#peekLine,Stream,TaintedString>`_
+  runnableExamples:
+    var strm = newStringStream("The first line\nthe second line\nthe third line")
+    var line = ""
+    doAssert strm.readLine(line) == true
+    doAssert line == "The first line"
+    doAssert strm.readLine(line) == true
+    doAssert line == "the second line"
+    doAssert strm.readLine(line) == true
+    doAssert line == "the third line"
+    doAssert strm.readLine(line) == false
+    doAssert line == ""
+    strm.close()
+
   line.string.setLen(0)
   while true:
     var c = readChar(s)
@@ -297,19 +879,53 @@ proc readLine*(s: Stream, line: var TaintedString): bool =
   result = true
 
 proc peekLine*(s: Stream, line: var TaintedString): bool =
-  ## peeks a line of text from the stream `s` into `line`. `line` must not be
+  ## Peeks a line of text from the stream `s` into `line`. `line` must not be
   ## ``nil``! May throw an IO exception.
+  ##
   ## A line of text may be delimited by ``CR``, ``LF`` or
   ## ``CRLF``. The newline character(s) are not part of the returned string.
   ## Returns ``false`` if the end of the file has been reached, ``true``
   ## otherwise. If ``false`` is returned `line` contains no new data.
+  ##
+  ## See also:
+  ## * `readLine(Stream) proc <#readLine,Stream>`_
+  ## * `readLine(Stream, TaintedString) proc <#readLine,Stream,TaintedString>`_
+  ## * `peekLine(Stream) proc <#peekLine,Stream>`_
+  runnableExamples:
+    var strm = newStringStream("The first line\nthe second line\nthe third line")
+    var line = ""
+    doAssert strm.peekLine(line) == true
+    doAssert line == "The first line"
+    doAssert strm.peekLine(line) == true
+    ## not "the second line"
+    doAssert line == "The first line"
+    doAssert strm.readLine(line) == true
+    doAssert line == "The first line"
+    doAssert strm.peekLine(line) == true
+    doAssert line == "the second line"
+    strm.close()
+
   let pos = getPosition(s)
   defer: setPosition(s, pos)
   result = readLine(s, line)
 
 proc readLine*(s: Stream): TaintedString =
-  ## Reads a line from a stream `s`. Note: This is not very efficient. Raises
-  ## `IOError` if an error occurred.
+  ## Reads a line from a stream `s`. Raises `IOError` if an error occurred.
+  ##
+  ## **Note:** This is not very efficient.
+  ##
+  ## See also:
+  ## * `readLine(Stream, TaintedString) proc <#readLine,Stream,TaintedString>`_
+  ## * `peekLine(Stream) proc <#peekLine,Stream>`_
+  ## * `peekLine(Stream, TaintedString) proc <#peekLine,Stream,TaintedString>`_
+  runnableExamples:
+    var strm = newStringStream("The first line\nthe second line\nthe third line")
+    doAssert strm.readLine() == "The first line"
+    doAssert strm.readLine() == "the second line"
+    doAssert strm.readLine() == "the third line"
+    doAssertRaises(IOError): discard strm.readLine()
+    strm.close()
+
   result = TaintedString""
   if s.atEnd:
     raise newEIO("cannot read from stream")
@@ -324,8 +940,23 @@ proc readLine*(s: Stream): TaintedString =
       result.string.add(c)
 
 proc peekLine*(s: Stream): TaintedString =
-  ## Peeks a line from a stream `s`. Note: This is not very efficient. Raises
-  ## `IOError` if an error occurred.
+  ## Peeks a line from a stream `s`. Raises `IOError` if an error occurred.
+  ##
+  ## **Note:** This is not very efficient.
+  ##
+  ## See also:
+  ## * `readLine(Stream) proc <#readLine,Stream>`_
+  ## * `readLine(Stream, TaintedString) proc <#readLine,Stream,TaintedString>`_
+  ## * `peekLine(Stream, TaintedString) proc <#peekLine,Stream,TaintedString>`_
+  runnableExamples:
+    var strm = newStringStream("The first line\nthe second line\nthe third line")
+    doAssert strm.peekLine() == "The first line"
+    ## not "the second line"
+    doAssert strm.peekLine() == "The first line"
+    doAssert strm.readLine() == "The first line"
+    doAssert strm.peekLine() == "the second line"
+    strm.close()
+
   let pos = getPosition(s)
   defer: setPosition(s, pos)
   result = readLine(s)
@@ -333,6 +964,18 @@ proc peekLine*(s: Stream): TaintedString =
 iterator lines*(s: Stream): TaintedString =
   ## Iterates over every line in the stream.
   ## The iteration is based on ``readLine``.
+  ##
+  ## See also:
+  ## * `readLine(Stream) proc <#readLine,Stream>`_
+  ## * `readLine(Stream, TaintedString) proc <#readLine,Stream,TaintedString>`_
+  runnableExamples:
+    var strm = newStringStream("The first line\nthe second line\nthe third line")
+    var lines: seq[string]
+    for line in strm.lines():
+      lines.add line
+    doAssert lines == @["The first line", "the second line", "the third line"]
+    strm.close()
+
   var line: TaintedString
   while s.readLine(line):
     yield line
@@ -340,9 +983,16 @@ iterator lines*(s: Stream): TaintedString =
 when not defined(js):
 
   type
-    StringStream* = ref StringStreamObj ## a stream that encapsulates a string
+    StringStream* = ref StringStreamObj
+      ## A stream that encapsulates a string.
+      ##
+      ## **Note:** Not available for JS backend.
     StringStreamObj* = object of StreamObj
-      data*: string
+      ## A string stream object.
+      ##
+      ## **Note:** Not available for JS backend.
+      data*: string ## A string data.
+                    ## This is updated when called `writeLine` etc.
       pos: int
 
   proc ssAtEnd(s: Stream): bool =
@@ -404,7 +1054,24 @@ when not defined(js):
       s.data = nil
 
   proc newStringStream*(s: string = ""): owned StringStream =
-    ## creates a new stream from the string `s`.
+    ## Creates a new stream from the string `s`.
+    ##
+    ## **Note:** Not available for JS backend.
+    ##
+    ## See also:
+    ## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from
+    ##   opened File.
+    ## * `newFileStream proc <#newFileStream,string,FileMode,int>`_  creates a
+    ##   file stream from the file name and the mode.
+    ## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a
+    ##   file stream from the file name and the mode.
+    runnableExamples:
+      var strm = newStringStream("The first line\nthe second line\nthe third line")
+      doAssert strm.readLine() == "The first line"
+      doAssert strm.readLine() == "the second line"
+      doAssert strm.readLine() == "the third line"
+      strm.close()
+
     new(result)
     result.data = s
     result.pos = 0
@@ -418,8 +1085,14 @@ when not defined(js):
     result.readDataStrImpl = ssReadDataStr
 
   type
-    FileStream* = ref FileStreamObj ## a stream that encapsulates a `File`
+    FileStream* = ref FileStreamObj
+      ## A stream that encapsulates a `File`.
+      ##
+      ## **Note:** Not available for JS backend.
     FileStreamObj* = object of Stream
+      ## A file stream object.
+      ##
+      ## **Note:** Not available for JS backend.
       f: File
 
   proc fsClose(s: Stream) =
@@ -447,7 +1120,35 @@ when not defined(js):
       raise newEIO("cannot write to stream")
 
   proc newFileStream*(f: File): owned FileStream =
-    ## creates a new stream from the file `f`.
+    ## Creates a new stream from the file `f`.
+    ##
+    ## **Note:** Not available for JS backend.
+    ##
+    ## See also:
+    ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream
+    ##   from string.
+    ## * `newFileStream proc <#newFileStream,string,FileMode,int>`_ is the same
+    ##   as using `open proc <system.html#open,File,string,FileMode,int>`_
+    ##   on Examples.
+    ## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a
+    ##   file stream from the file name and the mode.
+    runnableExamples:
+      ## Input (somefile.txt):
+      ## The first line
+      ## the second line
+      ## the third line
+      var f: File
+      if open(f, "somefile.txt", fmRead, -1):
+        var strm = newFileStream(f)
+        var line = ""
+        while strm.readLine(line):
+          echo line
+        ## Output:
+        ## The first line
+        ## the second line
+        ## the third line
+        strm.close()
+
     new(result)
     result.f = f
     result.closeImpl = fsClose
@@ -461,26 +1162,76 @@ when not defined(js):
     result.flushImpl = fsFlush
 
   proc newFileStream*(filename: string, mode: FileMode = fmRead, bufSize: int = -1): owned FileStream =
-    ## creates a new stream from the file named `filename` with the mode `mode`.
-    ## If the file cannot be opened, nil is returned. See the `system
-    ## <system.html>`_ module for a list of available FileMode enums.
-    ## **This function returns nil in case of failure. To prevent unexpected
-    ## behavior and ensure proper error handling, use openFileStream instead.**
+    ## Creates a new stream from the file named `filename` with the mode `mode`.
+    ##
+    ## If the file cannot be opened, `nil` is returned. See the `io module
+    ## <io.html>`_ for a list of available `FileMode enums <io.html#FileMode>`_.
+    ##
+    ## **Note:**
+    ## * **This function returns nil in case of failure.**
+    ##   To prevent unexpected behavior and ensure proper error handling,
+    ##   use `openFileStream proc <#openFileStream,string,FileMode,int>`_
+    ##   instead.
+    ## * Not available for JS backend.
+    ##
+    ## See also:
+    ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream
+    ##   from string.
+    ## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from
+    ##   opened File.
+    ## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a
+    ##   file stream from the file name and the mode.
+    runnableExamples:
+      from os import removeFile
+      var strm = newFileStream("somefile.txt", fmWrite)
+      if not isNil(strm):
+        strm.writeLine("The first line")
+        strm.writeLine("the second line")
+        strm.writeLine("the third line")
+        strm.close()
+        ## Output (somefile.txt)
+        ## The first line
+        ## the second line
+        ## the third line
+        removeFile("somefile.txt")
+
     var f: File
     if open(f, filename, mode, bufSize): result = newFileStream(f)
 
   proc openFileStream*(filename: string, mode: FileMode = fmRead, bufSize: int = -1): owned FileStream =
-    ## creates a new stream from the file named `filename` with the mode `mode`.
+    ## Creates a new stream from the file named `filename` with the mode `mode`.
     ## If the file cannot be opened, an IO exception is raised.
+    ##
+    ## **Note:** Not available for JS backend.
+    ##
+    ## See also:
+    ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream
+    ##   from string.
+    ## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from
+    ##   opened File.
+    ## * `newFileStream proc <#newFileStream,string,FileMode,int>`_  creates a
+    ##   file stream from the file name and the mode.
+    runnableExamples:
+      try:
+        ## Input (somefile.txt):
+        ## The first line
+        ## the second line
+        ## the third line
+        var strm = openFileStream("somefile.txt")
+        echo strm.readLine()
+        ## Output:
+        ## The first line
+        strm.close()
+      except:
+        stderr.write getCurrentExceptionMsg()
+
     var f: File
     if open(f, filename, mode, bufSize):
       return newFileStream(f)
     else:
-      raise newEIO("cannot open file")
+      raise newEIO("cannot open file\n")
 
-when true:
-  discard
-else:
+when false:
   type
     FileHandleStream* = ref FileHandleStreamObj
     FileHandleStreamObj* = object of Stream
diff --git a/lib/pure/strformat.nim b/lib/pure/strformat.nim
index 19fbf8ab3..fdf1753a8 100644
--- a/lib/pure/strformat.nim
+++ b/lib/pure/strformat.nim
@@ -419,6 +419,9 @@ proc formatValue*(result: var string; value: SomeInteger; specifier: string) =
   ## Standard format implementation for ``SomeInteger``. It makes little
   ## sense to call this directly, but it is required to exist
   ## by the ``&`` macro.
+  if specifier.len == 0:
+    result.add $value
+    return
   let spec = parseStandardFormatSpecifier(specifier)
   var radix = 10
   case spec.typ
@@ -432,10 +435,13 @@ proc formatValue*(result: var string; value: SomeInteger; specifier: string) =
       " of 'x', 'X', 'b', 'd', 'o' but got: " & spec.typ)
   result.add formatInt(value, radix, spec)
 
-proc formatValue*(result: var string; value: SomeFloat; specifier: string): void =
+proc formatValue*(result: var string; value: SomeFloat; specifier: string) =
   ## Standard format implementation for ``SomeFloat``. It makes little
   ## sense to call this directly, but it is required to exist
   ## by the ``&`` macro.
+  if specifier.len == 0:
+    result.add $value
+    return
   let spec = parseStandardFormatSpecifier(specifier)
 
   var fmode = ffDefault
@@ -457,7 +463,7 @@ proc formatValue*(result: var string; value: SomeFloat; specifier: string): void
   if value >= 0.0:
     if spec.sign != '-':
       sign = true
-      if  value == 0.0:
+      if value == 0.0:
         if 1.0 / value == Inf:
           # only insert the sign if value != negZero
           f.insert($spec.sign, 0)
@@ -467,16 +473,16 @@ proc formatValue*(result: var string; value: SomeFloat; specifier: string): void
     sign = true
 
   if spec.padWithZero:
-    var sign_str = ""
+    var signStr = ""
     if sign:
-      sign_str = $f[0]
+      signStr = $f[0]
       f = f[1..^1]
 
     let toFill = spec.minimumWidth - f.len - ord(sign)
     if toFill > 0:
       f = repeat('0', toFill) & f
     if sign:
-      f = sign_str & f
+      f = signStr & f
 
   # the default for numbers is right-alignment:
   let align = if spec.align == '\0': '>' else: spec.align
@@ -712,6 +718,13 @@ when isMainModule:
   for s in invalidUtf8:
     check &"{s:>5}", repeat(" ", 5-s.len) & s
 
+  # bug #11089
+  let flfoo: float = 1.0
+  check &"{flfoo}", "1.0"
+
+  # bug #11092
+  check &"{high(int64)}", "9223372036854775807"
+  check &"{low(int64)}", "-9223372036854775808"
 
   import json
 
diff --git a/lib/pure/times.nim b/lib/pure/times.nim
index 8074c09e8..dc79877fd 100644
--- a/lib/pure/times.nim
+++ b/lib/pure/times.nim
@@ -17,7 +17,8 @@
   resolution used by ``getTime()`` depends on the platform and backend
   (JS is limited to millisecond precision).
 
-  Examples:
+  Examples
+  ========
 
   .. code-block:: nim
     import times, os
@@ -38,7 +39,7 @@
     echo "One month from now     : ", now() + 1.months
 
   Parsing and Formatting Dates
-  ----------------------------
+  ============================
 
   The ``DateTime`` type can be parsed and formatted using the different
   ``parse`` and ``format`` procedures.
@@ -128,7 +129,7 @@
   only for years in the range 1..9999).
 
   Duration vs TimeInterval
-  ----------------------------
+  ============================
   The ``times`` module exports two similiar types that are both used to
   represent some amount of time: `Duration <#Duration>`_ and
   `TimeInterval <#TimeInterval>`_.
@@ -137,7 +138,7 @@
   needed).
 
   Duration
-  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  ----------------------------
   A ``Duration`` represents a duration of time stored as seconds and
   nanoseconds. A ``Duration`` is always fully normalized, so
 ``initDuration(hours = 1)`` and ``initDuration(minutes = 60)`` are equivilant.
@@ -147,7 +148,7 @@
   is more performant and easier to understand it should generally prefered.
 
   TimeInterval
-  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  ----------------------------
   A ``TimeInterval`` represents some amount of time expressed in calendar
   units, for example "1 year and 2 days". Since some units cannot be
   normalized (the length of a year is different for leap years for example),
@@ -164,7 +165,7 @@
   ``Duration`` doesn't have.
 
   How long is a day?
-  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  ----------------------------
   It should be especially noted that the handling of days differs between
   ``TimeInterval`` and ``Duration``. The ``Duration`` type always treats a day
   as exactly 86400 seconds. For ``TimeInterval``, it's more complex.
@@ -2651,7 +2652,7 @@ proc microseconds*(dur: Duration): int {.inline, deprecated.} =
     doAssert dur.microseconds == 7008
   result = convert(Nanoseconds, Microseconds, dur.nanosecond)
 
-proc nanoseconds*(dur: Duration): NanosecondRange {.inline.} =
+proc nanoseconds*(dur: Duration): NanosecondRange {.inline, deprecated.} =
   ## Number of whole microseconds represented by the **fractional**
   ## part of the duration.
   ##
diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim
index ce147cccc..60b20c5b8 100644
--- a/lib/pure/unittest.nim
+++ b/lib/pure/unittest.nim
@@ -57,8 +57,8 @@
 ##   # Run suites starting with 'bug #' and standalone tests starting with '#'
 ##   nim c -r test 'bug #*::' '::#*'
 ##
-## Example
-## -------
+## Examples
+## ========
 ##
 ## .. code:: nim
 ##
@@ -177,13 +177,13 @@ proc addOutputFormatter*(formatter: OutputFormatter) =
   formatters.add(formatter)
 
 proc newConsoleOutputFormatter*(outputLevel: OutputLevel = PRINT_ALL,
-                                colorOutput = true): ConsoleOutputFormatter =
+                                colorOutput = true): <//>ConsoleOutputFormatter =
   ConsoleOutputFormatter(
     outputLevel: outputLevel,
     colorOutput: colorOutput
   )
 
-proc defaultConsoleFormatter*(): ConsoleOutputFormatter =
+proc defaultConsoleFormatter*(): <//>ConsoleOutputFormatter =
   when declared(stdout):
     # Reading settings
     # On a terminal this branch is executed
@@ -263,7 +263,7 @@ proc xmlEscape(s: string): string =
       else:
         result.add(c)
 
-proc newJUnitOutputFormatter*(stream: Stream): JUnitOutputFormatter =
+proc newJUnitOutputFormatter*(stream: Stream): <//>JUnitOutputFormatter =
   ## Creates a formatter that writes report to the specified stream in
   ## JUnit format.
   ## The ``stream`` is NOT closed automatically when the test are finished,
diff --git a/lib/system.nim b/lib/system.nim
index a04433530..bf2e156b4 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1619,7 +1619,7 @@ template `isnot`*(x, y: untyped): untyped = not (x is y)
   ##   assert @[1, 2] isnot enum
 
 when defined(nimV2) and not defined(nimscript):
-  type owned*{.magic: "BuiltinType".}[T]
+  type owned*{.magic: "BuiltinType".}[T] ## type constructor to mark a ref/ptr or a closure as `owned`.
 
   proc new*[T](a: var owned(ref T)) {.magic: "New", noSideEffect.}
     ## Creates a new object of type ``T`` and returns a safe (traced)
@@ -1637,8 +1637,16 @@ when defined(nimV2) and not defined(nimscript):
       var r: owned(ref t)
     new(r)
     return r
+
+  proc unown*[T](x: T): T {.magic: "Unown", noSideEffect.}
+    ## Use the expression ``x`` ignoring its ownership attribute.
+
+  # This is only required to make 0.20 compile with the 0.19 line.
+  template `<//>`*(t: untyped): untyped = owned(t)
+
 else:
   template owned*(t: typeDesc): typedesc = t
+  template unown*(x: typed): typed = x
 
   proc new*[T](a: var ref T) {.magic: "New", noSideEffect.}
     ## Creates a new object of type ``T`` and returns a safe (traced)
@@ -1657,6 +1665,9 @@ else:
     new(r)
     return r
 
+  # This is only required to make 0.20 compile with the 0.19 line.
+  template `<//>`*(t: untyped): untyped = t
+
 template disarm*(x: typed) =
   ## Useful for ``disarming`` dangling pointers explicitly for the
   ## --newruntime. Regardless of whether --newruntime is used or not
@@ -1926,13 +1937,11 @@ const
     ## failure.
 
 when defined(nodejs) and not defined(nimscript):
-  var programResult* {.importc: "process.exitCode".}: int
+  var programResult* {.importc: "process.exitCode", deprecated.}: int
   programResult = 0
-else:
-  var programResult* {.compilerproc, exportc: "nim_program_result".}: int
-    ## Modify this variable to specify the exit code of the program
-    ## under normal circumstances. When the program is terminated
-    ## prematurely using `quit proc <#quit,int>`_, this value is ignored.
+elif hostOS != "standalone":
+  var programResult* {.compilerproc, exportc: "nim_program_result", deprecated.}: int
+    ## deprecated, prefer ``quit``
 
 when defined(nimdoc):
   proc quit*(errorcode: int = QuitSuccess) {.magic: "Exit", noreturn.}
@@ -1994,18 +2003,7 @@ when not defined(JS) and not defined(nimscript) and hostOS != "standalone":
 when not defined(JS) and not defined(nimscript) and hasAlloc and not defined(gcDestructors):
   proc addChar(s: NimString, c: char): NimString {.compilerProc, benign.}
 
-when defined(gcDestructors):
-  proc add*[T](x: var seq[T], y: sink T) {.magic: "AppendSeqElem", noSideEffect.} =
-    ## Generic proc for adding a data item `y` to a container `x`.
-    ##
-    ## For containers that have an order, `add` means *append*. New generic
-    ## containers should also call their adding proc `add` for consistency.
-    ## Generic code becomes much easier to write if the Nim naming scheme is
-    ## respected.
-    let xl = x.len
-    setLen(x, xl + 1)
-    x[xl] = y
-else:
+when not defined(gcDestructors):
   proc add*[T](x: var seq[T], y: T) {.magic: "AppendSeqElem", noSideEffect.}
     ## Generic proc for adding a data item `y` to a container `x`.
     ##
@@ -2239,14 +2237,15 @@ proc addQuitProc*(quitProc: proc() {.noconv.}) {.
 # not be called explicitly! The user may decide to do this manually though.
 
 when not defined(nimscript) and not defined(JS):
-  proc zeroMem*(p: pointer, size: Natural) {.inline, benign.}
+  proc zeroMem*(p: pointer, size: Natural) {.inline, noSideEffect,
+    tags: [], locks: 0, raises: [].}
     ## Overwrites the contents of the memory at ``p`` with the value 0.
     ##
     ## Exactly ``size`` bytes will be overwritten. Like any procedure
     ## dealing with raw memory this is **unsafe**.
 
   proc copyMem*(dest, source: pointer, size: Natural) {.inline, benign,
-    tags: [], locks: 0.}
+    tags: [], locks: 0, raises: [].}
     ## Copies the contents from the memory at ``source`` to the memory
     ## at ``dest``.
     ## Exactly ``size`` bytes will be copied. The memory
@@ -2254,7 +2253,7 @@ when not defined(nimscript) and not defined(JS):
     ## memory this is **unsafe**.
 
   proc moveMem*(dest, source: pointer, size: Natural) {.inline, benign,
-    tags: [], locks: 0.}
+    tags: [], locks: 0, raises: [].}
     ## Copies the contents from the memory at ``source`` to the memory
     ## at ``dest``.
     ##
@@ -2263,7 +2262,8 @@ when not defined(nimscript) and not defined(JS):
     ## and is thus somewhat more safe than ``copyMem``. Like any procedure
     ## dealing with raw memory this is still **unsafe**, though.
 
-  proc equalMem*(a, b: pointer, size: Natural): bool {.inline, noSideEffect, tags: [], locks: 0.}
+  proc equalMem*(a, b: pointer, size: Natural): bool {.inline, noSideEffect,
+    tags: [], locks: 0, raises: [].}
     ## Compares the memory blocks ``a`` and ``b``. ``size`` bytes will
     ## be compared.
     ##
diff --git a/lib/system/ansi_c.nim b/lib/system/ansi_c.nim
index 23828af91..99f66961d 100644
--- a/lib/system/ansi_c.nim
+++ b/lib/system/ansi_c.nim
@@ -148,4 +148,4 @@ proc rawWrite*(f: CFilePtr, s: cstring) {.compilerproc, nonreloadable, inline.}
   # we cannot throw an exception here!
   discard c_fwrite(s, 1, s.len, f)
 
-{.pop}
+{.pop.}
diff --git a/lib/system/fatal.nim b/lib/system/fatal.nim
index 100b6d482..82704a2e7 100644
--- a/lib/system/fatal.nim
+++ b/lib/system/fatal.nim
@@ -10,6 +10,8 @@ when hostOS == "standalone":
     panic(arg)
 
 elif defined(nimQuirky) and not defined(nimscript):
+  import ansi_c
+
   proc name(t: typedesc): string {.magic: "TypeTrait".}
 
   proc sysFatal(exceptn: typedesc, message, arg: string) {.inline, noReturn.} =
diff --git a/lib/system/strmantle.nim b/lib/system/strmantle.nim
index 727c08da3..4aa1b705f 100644
--- a/lib/system/strmantle.nim
+++ b/lib/system/strmantle.nim
@@ -147,58 +147,58 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
     has_sign = false
 
   # Sign?
-  if s[i] == '+' or s[i] == '-':
+  if i < s.len and (s[i] == '+' or s[i] == '-'):
     has_sign = true
     if s[i] == '-':
       sign = -1.0
     inc(i)
 
   # NaN?
-  if s[i] == 'N' or s[i] == 'n':
+  if i+2 < s.len and (s[i] == 'N' or s[i] == 'n'):
     if s[i+1] == 'A' or s[i+1] == 'a':
       if s[i+2] == 'N' or s[i+2] == 'n':
-        if s[i+3] notin IdentChars:
+        if i+3 >= s.len or s[i+3] notin IdentChars:
           number = NaN
           return i+3 - start
     return 0
 
   # Inf?
-  if s[i] == 'I' or s[i] == 'i':
+  if i+2 < s.len and (s[i] == 'I' or s[i] == 'i'):
     if s[i+1] == 'N' or s[i+1] == 'n':
       if s[i+2] == 'F' or s[i+2] == 'f':
-        if s[i+3] notin IdentChars:
+        if i+3 >= s.len or s[i+3] notin IdentChars:
           number = Inf*sign
           return i+3 - start
     return 0
 
-  if s[i] in {'0'..'9'}:
+  if i < s.len and s[i] in {'0'..'9'}:
     first_digit = (s[i].ord - '0'.ord)
   # Integer part?
-  while s[i] in {'0'..'9'}:
+  while i < s.len and s[i] in {'0'..'9'}:
     inc(kdigits)
     integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64
     inc(i)
-    while s[i] == '_': inc(i)
+    while i < s.len and s[i] == '_': inc(i)
 
   # Fractional part?
-  if s[i] == '.':
+  if i < s.len and s[i] == '.':
     inc(i)
     # if no integer part, Skip leading zeros
     if kdigits <= 0:
-      while s[i] == '0':
+      while i < s.len and s[i] == '0':
         inc(frac_exponent)
         inc(i)
-        while s[i] == '_': inc(i)
+        while i < s.len and s[i] == '_': inc(i)
 
-    if first_digit == -1 and s[i] in {'0'..'9'}:
+    if first_digit == -1 and i < s.len and s[i] in {'0'..'9'}:
       first_digit = (s[i].ord - '0'.ord)
     # get fractional part
-    while s[i] in {'0'..'9'}:
+    while i < s.len and s[i] in {'0'..'9'}:
       inc(fdigits)
       inc(frac_exponent)
       integer = integer * 10'u64 + (s[i].ord - '0'.ord).uint64
       inc(i)
-      while s[i] == '_': inc(i)
+      while i < s.len and s[i] == '_': inc(i)
 
   # if has no digits: return error
   if kdigits + fdigits <= 0 and
@@ -206,7 +206,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
      (i == start + 1 and has_sign)): # or only '+' or '-
     return 0
 
-  if s[i] in {'e', 'E'}:
+  if i+1 < s.len and s[i] in {'e', 'E'}:
     inc(i)
     if s[i] == '+' or s[i] == '-':
       if s[i] == '-':
@@ -215,10 +215,10 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
       inc(i)
     if s[i] notin {'0'..'9'}:
       return 0
-    while s[i] in {'0'..'9'}:
+    while i < s.len and s[i] in {'0'..'9'}:
       exponent = exponent * 10 + (ord(s[i]) - ord('0'))
       inc(i)
-      while s[i] == '_': inc(i) # underscores are allowed and ignored
+      while i < s.len and s[i] == '_': inc(i) # underscores are allowed and ignored
 
   var real_exponent = exp_sign*exponent - frac_exponent
   let exp_negative = real_exponent < 0
@@ -259,12 +259,12 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
   result = i - start
   i = start
   # re-parse without error checking, any error should be handled by the code above.
-  if s[i] == '.': i.inc
-  while s[i] in {'0'..'9','+','-'}:
+  if i < s.len and s[i] == '.': i.inc
+  while i < s.len and s[i] in {'0'..'9','+','-'}:
     if ti < maxlen:
       t[ti] = s[i]; inc(ti)
     inc(i)
-    while s[i] in {'.', '_'}: # skip underscore and decimal point
+    while i < s.len and s[i] in {'.', '_'}: # skip underscore and decimal point
       inc(i)
 
   # insert exponent
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index 18ceb900b..2c2fd4325 100644
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -19,7 +19,8 @@
 ## to prevent race conditions and improves efficiency. See `the manual for
 ## details of this memory model <manual.html#threads>`_.
 ##
-## Example:
+## Examples
+## ========
 ##
 ## .. code-block:: Nim
 ##
@@ -328,7 +329,7 @@ else:
 proc createThread*(t: var Thread[void], tp: proc () {.thread, nimcall.}) =
   createThread[void](t, tp)
 
-## we need to cache current threadId to not perform syscall all the time
+# we need to cache current threadId to not perform syscall all the time
 var threadId {.threadvar.}: int
 
 when defined(windows):