summary refs log tree commit diff stats
path: root/lib/pure/options.nim
diff options
context:
space:
mode:
authorkonsumlamm <44230978+konsumlamm@users.noreply.github.com>2021-02-18 11:10:50 +0100
committerGitHub <noreply@github.com>2021-02-18 02:10:50 -0800
commitf400b5c26b463b6636f3f62c4a32bf372a05db58 (patch)
tree429c24ed5c26823b4f76147697939f2a17d15716 /lib/pure/options.nim
parented0a4e731184393da1222980209e705f27bd6562 (diff)
downloadNim-f400b5c26b463b6636f3f62c4a32bf372a05db58.tar.gz
Improve documentation for options (#17036)
Diffstat (limited to 'lib/pure/options.nim')
-rw-r--r--lib/pure/options.nim234
1 files changed, 104 insertions, 130 deletions
diff --git a/lib/pure/options.nim b/lib/pure/options.nim
index 8eedcd082..7abfaa93a 100644
--- a/lib/pure/options.nim
+++ b/lib/pure/options.nim
@@ -13,7 +13,7 @@
 ## `some(x)`) or is empty (`none(T)`).
 ##
 ## This can be useful when you have a value that can be present or not. The
-## absence of a value is often represented by `nil`, but it is not always
+## absence of a value is often represented by `nil`, but that is not always
 ## available, nor is it always a good solution.
 ##
 ##
@@ -36,18 +36,12 @@ runnableExamples:
 
 ## The `get` operation demonstrated above returns the underlying value, or
 ## raises `UnpackDefect` if there is no value. Note that `UnpackDefect`
-## inherits from `system.Defect`, and should therefore never be caught.
-## Instead, rely on checking if the option contains a value with
+## inherits from `system.Defect` and should therefore never be caught.
+## Instead, rely on checking if the option contains a value with the
 ## `isSome <#isSome,Option[T]>`_ and `isNone <#isNone,Option[T]>`_ procs.
-## 
-## How to deal with an absence of a value:
 
-runnableExamples:
-  let result = none(int)
-  # It has no value:
-  assert(result.isNone)
 
-import typetraits
+import std/typetraits
 
 when (NimMajor, NimMinor) >= (1, 1):
   type
@@ -58,7 +52,9 @@ else:
 
 type
   Option*[T] = object
-    ## An optional type that stores its value and state separately in a boolean.
+    ## An optional type that may or may not contain a value of type `T`.
+    ## When `T` is a a pointer type (`ptr`, `pointer`, `ref` or `proc`),
+    ## `none(T)` is represented as `nil`.
     when T is SomePointer:
       val: T
     else:
@@ -69,21 +65,20 @@ type
   UnpackError* {.deprecated: "See corresponding Defect".} = UnpackDefect
 
 proc option*[T](val: T): Option[T] {.inline.} =
-  ## Can be used to convert a pointer type (`ptr` or `ref` or `proc`) to an option type.
-  ## It converts `nil` to `None`.
+  ## Can be used to convert a pointer type (`ptr`, `pointer`, `ref` or `proc`) to an option type.
+  ## It converts `nil` to `none(T)`. When `T` is no pointer type, this is equivalent to `some(val)`.
   ##
-  ## See also:
-  ## * `some <#some,T>`_
-  ## * `none <#none,typedesc>`_
+  ## **See also:**
+  ## * `some proc <#some,T>`_
+  ## * `none proc <#none,typedesc>`_
   runnableExamples:
     type
       Foo = ref object
         a: int
         b: string
-    var c: Foo
-    assert c.isNil
-    var d = option(c)
-    assert d.isNone
+
+    assert option[Foo](nil).isNone
+    assert option(42).isSome
 
   result.val = val
   when T isnot SomePointer:
@@ -92,21 +87,18 @@ proc option*[T](val: T): Option[T] {.inline.} =
 proc some*[T](val: T): Option[T] {.inline.} =
   ## Returns an `Option` that has the value `val`.
   ##
-  ## See also:
-  ## * `option <#option,T>`_
-  ## * `none <#none,typedesc>`_
-  ## * `isSome <#isSome,Option[T]>`_
+  ## **See also:**
+  ## * `option proc <#option,T>`_
+  ## * `none proc <#none,typedesc>`_
+  ## * `isSome proc <#isSome,Option[T]>`_
   runnableExamples:
-    var
-      a = some("abc")
-      b = some(42)
-    assert $typeof(a) == "Option[system.string]"
-    assert b.isSome
+    let a = some("abc")
+
+    assert a.isSome
     assert a.get == "abc"
-    assert $b == "Some(42)"
 
   when T is SomePointer:
-    assert(not val.isNil)
+    assert not val.isNil
     result.val = val
   else:
     result.has = true
@@ -115,30 +107,29 @@ proc some*[T](val: T): Option[T] {.inline.} =
 proc none*(T: typedesc): Option[T] {.inline.} =
   ## Returns an `Option` for this type that has no value.
   ##
-  ## See also:
-  ## * `option <#option,T>`_
-  ## * `some <#some,T>`_
-  ## * `isNone <#isNone,Option[T]>`_
+  ## **See also:**
+  ## * `option proc <#option,T>`_
+  ## * `some proc <#some,T>`_
+  ## * `isNone proc <#isNone,Option[T]>`_
   runnableExamples:
-    var a = none(int)
-    assert a.isNone
-    assert $typeof(a) == "Option[system.int]"
+    assert none(int).isNone
 
   # the default is the none type
   discard
 
 proc none*[T]: Option[T] {.inline.} =
-  ## Alias for `none(T) proc <#none,typedesc>`_.
+  ## Alias for `none(T) <#none,typedesc>`_.
   none(T)
 
 proc isSome*[T](self: Option[T]): bool {.inline.} =
   ## Checks if an `Option` contains a value.
+  ##
+  ## **See also:**
+  ## * `isNone proc <#isNone,Option[T]>`_
+  ## * `some proc <#some,T>`_
   runnableExamples:
-    var
-      a = some(42)
-      b = none(string)
-    assert a.isSome
-    assert not b.isSome
+    assert some(42).isSome
+    assert not none(string).isSome
 
   when T is SomePointer:
     not self.val.isNil
@@ -147,44 +138,40 @@ proc isSome*[T](self: Option[T]): bool {.inline.} =
 
 proc isNone*[T](self: Option[T]): bool {.inline.} =
   ## Checks if an `Option` is empty.
+  ##
+  ## **See also:**
+  ## * `isSome proc <#isSome,Option[T]>`_
+  ## * `none proc <#none,typedesc>`_
   runnableExamples:
-    var
-      a = some(42)
-      b = none(string)
-    assert not a.isNone
-    assert b.isNone
+    assert not some(42).isNone
+    assert none(string).isNone
+
   when T is SomePointer:
     self.val.isNil
   else:
     not self.has
 
 proc get*[T](self: Option[T]): lent T {.inline.} =
-  ## Returns contents of an `Option`. If it is `None`, then an exception is
-  ## thrown.
+  ## Returns the content of an `Option`. If it has no value,
+  ## an `UnpackDefect` exception is raised.
   ##
-  ## See also:
-  ## * `get proc <#get,Option[T],T>`_ with the default return value
+  ## **See also:**
+  ## * `get proc <#get,Option[T],T>`_ with a default return value
   runnableExamples:
-    let
-      a = some(42)
-      b = none(string)
-    assert a.get == 42
+    assert some(42).get == 42
     doAssertRaises(UnpackDefect):
-      echo b.get
+      echo none(string).get
 
   if self.isNone:
     raise newException(UnpackDefect, "Can't obtain a value from a `none`")
   result = self.val
 
 proc get*[T](self: Option[T], otherwise: T): T {.inline.} =
-  ## Returns the contents of the `Option` or an `otherwise` value if
-  ## the `Option` is `None`.
+  ## Returns the content of the `Option` or `otherwise` if
+  ## the `Option` has no value.
   runnableExamples:
-    var
-      a = some(42)
-      b = none(int)
-    assert a.get(9999) == 42
-    assert b.get(9999) == 9999
+    assert some(42).get(9999) == 42
+    assert none(int).get(9999) == 9999
 
   if self.isSome:
     self.val
@@ -192,13 +179,14 @@ proc get*[T](self: Option[T], otherwise: T): T {.inline.} =
     otherwise
 
 proc get*[T](self: var Option[T]): var T {.inline.} =
-  ## Returns contents of the `var Option`. If it is `None`, then an exception
-  ## is thrown.
+  ## Returns the content of the `var Option` mutably. If it has no value,
+  ## an `UnpackDefect` exception is raised.
   runnableExamples:
-    let
+    var
       a = some(42)
       b = none(string)
-    assert a.get == 42
+    inc(a.get)
+    assert a.get == 43
     doAssertRaises(UnpackDefect):
       echo b.get
 
@@ -209,22 +197,17 @@ proc get*[T](self: var Option[T]): var T {.inline.} =
 proc map*[T](self: Option[T], callback: proc (input: T)) {.inline.} =
   ## Applies a `callback` function to the value of the `Option`, if it has one.
   ##
-  ## See also:
+  ## **See also:**
   ## * `map proc <#map,Option[T],proc(T)_2>`_ for a version with a callback
   ##   which returns a value
-  ## * `filter proc <#filter,Option[T],proc(T)>`_
   runnableExamples:
     var d = 0
     proc saveDouble(x: int) =
-      d = 2*x
-
-    let
-      a = some(42)
-      b = none(int)
+      d = 2 * x
 
-    b.map(saveDouble)
+    none(int).map(saveDouble)
     assert d == 0
-    a.map(saveDouble)
+    some(42).map(saveDouble)
     assert d == 84
 
   if self.isSome:
@@ -234,49 +217,45 @@ proc map*[T, R](self: Option[T], callback: proc (input: T): R): Option[R] {.inli
   ## Applies a `callback` function to the value of the `Option` and returns an
   ## `Option` containing the new value.
   ##
-  ## If the `Option` is `None`, `None` of the return type of the `callback`
-  ## will be returned.
+  ## If the `Option` has no value, `none(R)` will be returned.
   ##
-  ## See also:
-  ## * `flatMap proc <#flatMap,Option[A],proc(A)>`_ for a version with a
-  ##   callback which returns an `Option`
-  ## * `filter proc <#filter,Option[T],proc(T)>`_
+  ## **See also:**
+  ## * `map proc <#map,Option[T],proc(T)>`_
+  ## * `flatMap proc <#flatMap,Option[T],proc(T)>`_ for a version with a
+  ##   callback that returns an `Option`
   runnableExamples:
-    var
-      a = some(42)
-      b = none(int)
-
     proc isEven(x: int): bool =
       x mod 2 == 0
 
-    assert $(a.map(isEven)) == "Some(true)"
-    assert $(b.map(isEven)) == "None[bool]"
+    assert some(42).map(isEven) == some(true)
+    assert none(int).map(isEven) == none(bool)
 
   if self.isSome:
     some[R](callback(self.val))
   else:
     none(R)
 
-proc flatten*[A](self: Option[Option[A]]): Option[A] {.inline.} =
+proc flatten*[T](self: Option[Option[T]]): Option[T] {.inline.} =
   ## Remove one level of structure in a nested `Option`.
+  ##
+  ## **See also:**
+  ## * `flatMap proc <#flatMap,Option[T],proc(T)>`_
   runnableExamples:
-    let a = some(some(42))
-    assert $flatten(a) == "Some(42)"
+    assert flatten(some(some(42))) == some(42)
+    assert flatten(none(Option[int])) == none(int)
 
   if self.isSome:
     self.val
   else:
-    none(A)
+    none(T)
 
-proc flatMap*[A, B](self: Option[A],
-                    callback: proc (input: A): Option[B]): Option[B] {.inline.} =
-  ## Applies a `callback` function to the value of the `Option` and returns an
-  ## `Option` containing the new value.
+proc flatMap*[T, R](self: Option[T],
+                    callback: proc (input: T): Option[R]): Option[R] {.inline.} =
+  ## Applies a `callback` function to the value of the `Option` and returns the new value.
   ##
-  ## If the `Option` is `None`, `None` of the return type of the `callback`
-  ## will be returned.
+  ## If the `Option` has no value, `none(R)` will be returned.
   ##
-  ## Similar to `map`, with the difference that the `callback` returns an
+  ## This is similar to `map`, with the difference that the `callback` returns an
   ## `Option`, not a raw value. This allows multiple procs with a
   ## signature of `A -> Option[B]` to be chained together.
   ##
@@ -286,16 +265,13 @@ proc flatMap*[A, B](self: Option[A],
   runnableExamples:
     proc doublePositives(x: int): Option[int] =
       if x > 0:
-        return some(2*x)
+        some(2 * x)
       else:
-        return none(int)
-    let
-      a = some(42)
-      b = none(int)
-      c = some(-11)
-    assert a.flatMap(doublePositives) == some(84)
-    assert b.flatMap(doublePositives) == none(int)
-    assert c.flatMap(doublePositives) == none(int)
+        none(int)
+
+    assert some(42).flatMap(doublePositives) == some(84)
+    assert none(int).flatMap(doublePositives) == none(int)
+    assert some(-11).flatMap(doublePositives) == none(int)
 
   map(self, callback).flatten()
 
@@ -305,26 +281,22 @@ proc filter*[T](self: Option[T], callback: proc (input: T): bool): Option[T] {.i
   ## If the `callback` returns `true`, the option is returned as `Some`.
   ## If it returns `false`, it is returned as `None`.
   ##
-  ## See also:
-  ## * `map proc <#map,Option[T],proc(T)_2>`_
+  ## **See also:**
   ## * `flatMap proc <#flatMap,Option[A],proc(A)>`_
   runnableExamples:
     proc isEven(x: int): bool =
       x mod 2 == 0
-    let
-      a = some(42)
-      b = none(int)
-      c = some(-11)
-    assert a.filter(isEven) == some(42)
-    assert b.filter(isEven) == none(int)
-    assert c.filter(isEven) == none(int)
+
+    assert some(42).filter(isEven) == some(42)
+    assert none(int).filter(isEven) == none(int)
+    assert some(-11).filter(isEven) == none(int)
 
   if self.isSome and not callback(self.val):
     none(T)
   else:
     self
 
-proc `==`*(a, b: Option): bool {.inline.} =
+proc `==`*[T](a, b: Option[T]): bool {.inline.} =
   ## Returns `true` if both `Option`s are `None`,
   ## or if they are both `Some` and have equal values.
   runnableExamples:
@@ -338,15 +310,17 @@ proc `==`*(a, b: Option): bool {.inline.} =
     assert b == d
     assert not (a == b)
 
-  (a.isSome and b.isSome and a.val == b.val) or (not a.isSome and not b.isSome)
+  when T is SomePointer:
+    a.val == b.val
+  else:
+    (a.isSome and b.isSome and a.val == b.val) or (a.isNone and b.isNone)
 
 proc `$`*[T](self: Option[T]): string =
   ## Get the string representation of the `Option`.
-  ##
-  ## If the `Option` has a value, the result will be `Some(x)` where `x`
-  ## is the string representation of the contained value.
-  ## If the `Option` does not have a value, the result will be `None[T]`
-  ## where `T` is the name of the type contained in the `Option`.
+  runnableExamples:
+    assert $some(42) == "Some(42)"
+    assert $none(int) == "None[int]"
+
   if self.isSome:
     result = "Some("
     result.addQuoted self.val
@@ -355,10 +329,10 @@ proc `$`*[T](self: Option[T]): string =
     result = "None[" & name(T) & "]"
 
 proc unsafeGet*[T](self: Option[T]): lent T {.inline.}=
-  ## Returns the value of a `some`. Behavior is undefined for `none`.
+  ## Returns the value of a `Some`. The behavior is undefined for `None`.
   ##
-  ## **Note:** Use it only when you are **absolutely sure** the value is present
-  ## (e.g. after checking `isSome <#isSome,Option[T]>`_).
-  ## Generally, using `get proc <#get,Option[T]>`_ is preferred.
+  ## **Note:** Use this only when you are **absolutely sure** the value is present
+  ## (e.g. after checking with `isSome <#isSome,Option[T]>`_).
+  ## Generally, using the `get proc <#get,Option[T]>`_ is preferred.
   assert self.isSome
   result = self.val