options.nim 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2015 Nim Contributors
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module implements types which encapsulate an optional value.
  10. ##
  11. ## A value of type `Option[T]` either contains a value `x` (represented as
  12. ## `some(x)`) or is empty (`none(T)`).
  13. ##
  14. ## This can be useful when you have a value that can be present or not. The
  15. ## absence of a value is often represented by `nil`, but it is not always
  16. ## available, nor is it always a good solution.
  17. ##
  18. ##
  19. ## Basic usage
  20. ## ===========
  21. ##
  22. ## Let's start with an example: a procedure that finds the index of a character
  23. ## in a string.
  24. ##
  25. ## .. code-block:: nim
  26. ##
  27. ## import options
  28. ##
  29. ## proc find(haystack: string, needle: char): Option[int] =
  30. ## for i, c in haystack:
  31. ## if c == needle:
  32. ## return some(i)
  33. ## return none(int) # This line is actually optional,
  34. ## # because the default is empty
  35. ##
  36. ## .. code-block:: nim
  37. ##
  38. ## let found = "abc".find('c')
  39. ## assert found.isSome and found.get() == 2
  40. ##
  41. ## The `get` operation demonstrated above returns the underlying value, or
  42. ## raises `UnpackError` if there is no value. Note that `UnpackError`
  43. ## inherits from `system.Defect`, and should therefore never be caught.
  44. ## Instead, rely on checking if the option contains a value with
  45. ## `isSome <#isSome,Option[T]>`_ and `isNone <#isNone,Option[T]>`_ procs.
  46. ##
  47. ## How to deal with an absence of a value:
  48. ##
  49. ## .. code-block:: nim
  50. ##
  51. ## let result = "team".find('i')
  52. ##
  53. ## # Nothing was found, so the result is `none`.
  54. ## assert(result == none(int))
  55. ## # It has no value:
  56. ## assert(result.isNone)
  57. import typetraits
  58. type
  59. SomePointer = ref | ptr | pointer
  60. type
  61. Option*[T] = object
  62. ## An optional type that stores its value and state separately in a boolean.
  63. when T is SomePointer:
  64. val: T
  65. else:
  66. val: T
  67. has: bool
  68. UnpackError* = object of Defect
  69. proc option*[T](val: T): Option[T] =
  70. ## Can be used to convert a pointer type (`ptr` or `ref`) to an option type.
  71. ## It converts `nil` to `None`.
  72. ##
  73. ## See also:
  74. ## * `some <#some,T>`_
  75. ## * `none <#none,typedesc>`_
  76. runnableExamples:
  77. type
  78. Foo = ref object
  79. a: int
  80. b: string
  81. var c: Foo
  82. assert c.isNil
  83. var d = option(c)
  84. assert d.isNone
  85. result.val = val
  86. when T isnot SomePointer:
  87. result.has = true
  88. proc some*[T](val: T): Option[T] =
  89. ## Returns an `Option` that has the value `val`.
  90. ##
  91. ## See also:
  92. ## * `option <#option,T>`_
  93. ## * `none <#none,typedesc>`_
  94. ## * `isSome <#isSome,Option[T]>`_
  95. runnableExamples:
  96. var
  97. a = some("abc")
  98. b = some(42)
  99. assert $type(a) == "Option[system.string]"
  100. assert b.isSome
  101. assert a.get == "abc"
  102. assert $b == "Some(42)"
  103. when T is SomePointer:
  104. assert(not val.isNil)
  105. result.val = val
  106. else:
  107. result.has = true
  108. result.val = val
  109. proc none*(T: typedesc): Option[T] =
  110. ## Returns an `Option` for this type that has no value.
  111. ##
  112. ## See also:
  113. ## * `option <#option,T>`_
  114. ## * `some <#some,T>`_
  115. ## * `isNone <#isNone,Option[T]>`_
  116. runnableExamples:
  117. var a = none(int)
  118. assert a.isNone
  119. assert $type(a) == "Option[system.int]"
  120. # the default is the none type
  121. discard
  122. proc none*[T]: Option[T] =
  123. ## Alias for `none(T) proc <#none,typedesc>`_.
  124. none(T)
  125. proc isSome*[T](self: Option[T]): bool {.inline.} =
  126. ## Checks if an `Option` contains a value.
  127. runnableExamples:
  128. var
  129. a = some(42)
  130. b = none(string)
  131. assert a.isSome
  132. assert not b.isSome
  133. when T is SomePointer:
  134. not self.val.isNil
  135. else:
  136. self.has
  137. proc isNone*[T](self: Option[T]): bool {.inline.} =
  138. ## Checks if an `Option` is empty.
  139. runnableExamples:
  140. var
  141. a = some(42)
  142. b = none(string)
  143. assert not a.isNone
  144. assert b.isNone
  145. when T is SomePointer:
  146. self.val.isNil
  147. else:
  148. not self.has
  149. proc get*[T](self: Option[T]): T =
  150. ## Returns contents of an `Option`. If it is `None`, then an exception is
  151. ## thrown.
  152. ##
  153. ## See also:
  154. ## * `get proc <#get,Option[T],T>`_ with the default return value
  155. runnableExamples:
  156. let
  157. a = some(42)
  158. b = none(string)
  159. assert a.get == 42
  160. doAssertRaises(UnpackError):
  161. echo b.get
  162. if self.isNone:
  163. raise newException(UnpackError, "Can't obtain a value from a `none`")
  164. self.val
  165. proc get*[T](self: Option[T], otherwise: T): T =
  166. ## Returns the contents of the `Option` or an `otherwise` value if
  167. ## the `Option` is `None`.
  168. runnableExamples:
  169. var
  170. a = some(42)
  171. b = none(int)
  172. assert a.get(9999) == 42
  173. assert b.get(9999) == 9999
  174. if self.isSome:
  175. self.val
  176. else:
  177. otherwise
  178. proc get*[T](self: var Option[T]): var T =
  179. ## Returns contents of the `var Option`. If it is `None`, then an exception
  180. ## is thrown.
  181. runnableExamples:
  182. let
  183. a = some(42)
  184. b = none(string)
  185. assert a.get == 42
  186. doAssertRaises(UnpackError):
  187. echo b.get
  188. if self.isNone:
  189. raise newException(UnpackError, "Can't obtain a value from a `none`")
  190. return self.val
  191. proc map*[T](self: Option[T], callback: proc (input: T)) =
  192. ## Applies a `callback` function to the value of the `Option`, if it has one.
  193. ##
  194. ## See also:
  195. ## * `map proc <#map,Option[T],proc(T)_2>`_ for a version with a callback
  196. ## which returns a value
  197. ## * `filter proc <#filter,Option[T],proc(T)>`_
  198. runnableExamples:
  199. var d = 0
  200. proc saveDouble(x: int) =
  201. d = 2*x
  202. let
  203. a = some(42)
  204. b = none(int)
  205. b.map(saveDouble)
  206. assert d == 0
  207. a.map(saveDouble)
  208. assert d == 84
  209. if self.isSome:
  210. callback(self.val)
  211. proc map*[T, R](self: Option[T], callback: proc (input: T): R): Option[R] =
  212. ## Applies a `callback` function to the value of the `Option` and returns an
  213. ## `Option` containing the new value.
  214. ##
  215. ## If the `Option` is `None`, `None` of the return type of the `callback`
  216. ## will be returned.
  217. ##
  218. ## See also:
  219. ## * `flatMap proc <#flatMap,Option[A],proc(A)>`_ for a version with a
  220. ## callback which returns an `Option`
  221. ## * `filter proc <#filter,Option[T],proc(T)>`_
  222. runnableExamples:
  223. var
  224. a = some(42)
  225. b = none(int)
  226. proc isEven(x: int): bool =
  227. x mod 2 == 0
  228. assert $(a.map(isEven)) == "Some(true)"
  229. assert $(b.map(isEven)) == "None[bool]"
  230. if self.isSome:
  231. some[R](callback(self.val))
  232. else:
  233. none(R)
  234. proc flatten*[A](self: Option[Option[A]]): Option[A] =
  235. ## Remove one level of structure in a nested `Option`.
  236. runnableExamples:
  237. let a = some(some(42))
  238. assert $flatten(a) == "Some(42)"
  239. if self.isSome:
  240. self.val
  241. else:
  242. none(A)
  243. proc flatMap*[A, B](self: Option[A],
  244. callback: proc (input: A): Option[B]): Option[B] =
  245. ## Applies a `callback` function to the value of the `Option` and returns an
  246. ## `Option` containing the new value.
  247. ##
  248. ## If the `Option` is `None`, `None` of the return type of the `callback`
  249. ## will be returned.
  250. ##
  251. ## Similar to `map`, with the difference that the `callback` returns an
  252. ## `Option`, not a raw value. This allows multiple procs with a
  253. ## signature of `A -> Option[B]` to be chained together.
  254. ##
  255. ## See also:
  256. ## * `flatten proc <#flatten,Option[Option[A]]>`_
  257. ## * `filter proc <#filter,Option[T],proc(T)>`_
  258. runnableExamples:
  259. proc doublePositives(x: int): Option[int] =
  260. if x > 0:
  261. return some(2*x)
  262. else:
  263. return none(int)
  264. let
  265. a = some(42)
  266. b = none(int)
  267. c = some(-11)
  268. assert a.flatMap(doublePositives) == some(84)
  269. assert b.flatMap(doublePositives) == none(int)
  270. assert c.flatMap(doublePositives) == none(int)
  271. map(self, callback).flatten()
  272. proc filter*[T](self: Option[T], callback: proc (input: T): bool): Option[T] =
  273. ## Applies a `callback` to the value of the `Option`.
  274. ##
  275. ## If the `callback` returns `true`, the option is returned as `Some`.
  276. ## If it returns `false`, it is returned as `None`.
  277. ##
  278. ## See also:
  279. ## * `map proc <#map,Option[T],proc(T)_2>`_
  280. ## * `flatMap proc <#flatMap,Option[A],proc(A)>`_
  281. runnableExamples:
  282. proc isEven(x: int): bool =
  283. x mod 2 == 0
  284. let
  285. a = some(42)
  286. b = none(int)
  287. c = some(-11)
  288. assert a.filter(isEven) == some(42)
  289. assert b.filter(isEven) == none(int)
  290. assert c.filter(isEven) == none(int)
  291. if self.isSome and not callback(self.val):
  292. none(T)
  293. else:
  294. self
  295. proc `==`*(a, b: Option): bool =
  296. ## Returns `true` if both `Option`s are `None`,
  297. ## or if they are both `Some` and have equal values.
  298. runnableExamples:
  299. let
  300. a = some(42)
  301. b = none(int)
  302. c = some(42)
  303. d = none(int)
  304. assert a == c
  305. assert b == d
  306. assert not (a == b)
  307. (a.isSome and b.isSome and a.val == b.val) or (not a.isSome and not b.isSome)
  308. proc `$`*[T](self: Option[T]): string =
  309. ## Get the string representation of the `Option`.
  310. ##
  311. ## If the `Option` has a value, the result will be `Some(x)` where `x`
  312. ## is the string representation of the contained value.
  313. ## If the `Option` does not have a value, the result will be `None[T]`
  314. ## where `T` is the name of the type contained in the `Option`.
  315. if self.isSome:
  316. result = "Some("
  317. result.addQuoted self.val
  318. result.add ")"
  319. else:
  320. result = "None[" & name(T) & "]"
  321. proc unsafeGet*[T](self: Option[T]): T =
  322. ## Returns the value of a `some`. Behavior is undefined for `none`.
  323. ##
  324. ## **Note:** Use it only when you are **absolutely sure** the value is present
  325. ## (e.g. after checking `isSome <#isSome,Option[T]>`_).
  326. ## Generally, using `get proc <#get,Option[T]>`_ is preferred.
  327. assert self.isSome
  328. self.val
  329. when isMainModule:
  330. import unittest, sequtils
  331. # RefPerson is used to test that overloaded `==` operator is not called by
  332. # options. It is defined here in the global scope, because otherwise the test
  333. # will not even consider the `==` operator. Different bug?
  334. type RefPerson = ref object
  335. name: string
  336. proc `==`(a, b: RefPerson): bool =
  337. assert(not a.isNil and not b.isNil)
  338. a.name == b.name
  339. suite "options":
  340. # work around a bug in unittest
  341. let intNone = none(int)
  342. let stringNone = none(string)
  343. test "example":
  344. proc find(haystack: string, needle: char): Option[int] =
  345. for i, c in haystack:
  346. if c == needle:
  347. return some i
  348. check("abc".find('c').get() == 2)
  349. let result = "team".find('i')
  350. check result == intNone
  351. check result.isNone
  352. test "some":
  353. check some(6).get() == 6
  354. check some("a").unsafeGet() == "a"
  355. check some(6).isSome
  356. check some("a").isSome
  357. test "none":
  358. expect UnpackError:
  359. discard none(int).get()
  360. check(none(int).isNone)
  361. check(not none(string).isSome)
  362. test "equality":
  363. check some("a") == some("a")
  364. check some(7) != some(6)
  365. check some("a") != stringNone
  366. check intNone == intNone
  367. when compiles(some("a") == some(5)):
  368. check false
  369. when compiles(none(string) == none(int)):
  370. check false
  371. test "get with a default value":
  372. check(some("Correct").get("Wrong") == "Correct")
  373. check(stringNone.get("Correct") == "Correct")
  374. test "$":
  375. check($(some("Correct")) == "Some(\"Correct\")")
  376. check($(stringNone) == "None[string]")
  377. test "map with a void result":
  378. var procRan = 0
  379. some(123).map(proc (v: int) = procRan = v)
  380. check procRan == 123
  381. intNone.map(proc (v: int) = check false)
  382. test "map":
  383. check(some(123).map(proc (v: int): int = v * 2) == some(246))
  384. check(intNone.map(proc (v: int): int = v * 2).isNone)
  385. test "filter":
  386. check(some(123).filter(proc (v: int): bool = v == 123) == some(123))
  387. check(some(456).filter(proc (v: int): bool = v == 123).isNone)
  388. check(intNone.filter(proc (v: int): bool = check false).isNone)
  389. test "flatMap":
  390. proc addOneIfNotZero(v: int): Option[int] =
  391. if v != 0:
  392. result = some(v + 1)
  393. else:
  394. result = none(int)
  395. check(some(1).flatMap(addOneIfNotZero) == some(2))
  396. check(some(0).flatMap(addOneIfNotZero) == none(int))
  397. check(some(1).flatMap(addOneIfNotZero).flatMap(addOneIfNotZero) == some(3))
  398. proc maybeToString(v: int): Option[string] =
  399. if v != 0:
  400. result = some($v)
  401. else:
  402. result = none(string)
  403. check(some(1).flatMap(maybeToString) == some("1"))
  404. proc maybeExclaim(v: string): Option[string] =
  405. if v != "":
  406. result = some v & "!"
  407. else:
  408. result = none(string)
  409. check(some(1).flatMap(maybeToString).flatMap(maybeExclaim) == some("1!"))
  410. check(some(0).flatMap(maybeToString).flatMap(maybeExclaim) == none(string))
  411. test "SomePointer":
  412. var intref: ref int
  413. check(option(intref).isNone)
  414. intref.new
  415. check(option(intref).isSome)
  416. let tmp = option(intref)
  417. check(sizeof(tmp) == sizeof(ptr int))
  418. test "none[T]":
  419. check(none[int]().isNone)
  420. check(none(int) == none[int]())
  421. test "$ on typed with .name":
  422. type Named = object
  423. name: string
  424. let nobody = none(Named)
  425. check($nobody == "None[Named]")
  426. test "$ on type with name()":
  427. type Person = object
  428. myname: string
  429. let noperson = none(Person)
  430. check($noperson == "None[Person]")
  431. test "Ref type with overloaded `==`":
  432. let p = some(RefPerson.new())
  433. check p.isSome