-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
logical operators for option type #8369
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -67,6 +67,34 @@ | |
## assert(false) # This will not be reached | ||
## except UnpackError: # Because an exception is raised | ||
## discard | ||
## | ||
## When you have a value of type ``Option[T]`` and you want to have | ||
## it's value of type ``T``, you can access the value with ``get``. | ||
## If you don't provide a fallback value there will be an exception. | ||
## With the ``or`` operator you can chain together several expressions | ||
## of type ``Option[T]`` and the whole expression will evaluate the | ||
## operand from left to right until an the operand that is not | ||
## none. This operand will be returned. If all operands are none, then | ||
## the expression evaluates to none. For convenience the last operand | ||
## of such an expression does not need to be of type ``Option[T]``, it | ||
## can be just of type ``T`` for the last fallback. If that is the | ||
## case the whole expression will be of type ``T``, because it could | ||
## not evaluate to none anymore. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your docs, while appreciated, are far too verbose. Create a short, and to the point heading: ## Retrieving values from an option
## ========================
##
## Values can be retrieved in many ways, primarily using ``get`` or the ``or`` operator.
##
## Using ``get``
## --------------
##
## This is the simplest approach:
##
## ..code-block:: ....
##
##
## But it means there is an exception raised when the option isn't a ``some``.
##
## Using ``or``
## -------------
##
## .... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Short sentences, and short specific examples are always better than a huge paragraph and a huge example. |
||
## | ||
## .. code-block:: nim | ||
## | ||
## var myOpt: Option[string] | ||
## # Pick the first option that is not none. | ||
## myOpt = some("abc") or some("def") | ||
## assert myOpt == some("abc") | ||
## var myStr: string | ||
## # Pick the first option that is not none with final fallback. | ||
## myStr = none(string) or some("abc") or "fallback" | ||
## assert myStr == "abc" | ||
## myStr = none(string) or none(string) or "fallback" | ||
## assert myStr == "fallback" | ||
|
||
|
||
import typetraits | ||
|
||
type | ||
|
@@ -139,6 +167,26 @@ proc get*[T](self: Option[T], otherwise: T): T = | |
else: | ||
otherwise | ||
|
||
template `or`*[T](x: Option[T]; y: T): T = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If an inline proc is enough, I much prefer them than templates |
||
## When ``x`` is some return the content of ``x``. Otherwise | ||
## evaluate ``y`` and return it. This operator can be used to | ||
## convert a value of type ``Option[T]`` into a value of type ``T`` | ||
## by providing a fallback value in ``y``. | ||
let xx = x | ||
if xx.isSome: | ||
xx.val | ||
else: | ||
y | ||
|
||
template `or`*[T](x, y: Option[T]): Option[T] = | ||
## When ``x`` is some, then return ``x``, else return | ||
## ``y``. Evaluate ``y`` only when necessary. | ||
let xx = x | ||
if xx.isSome: | ||
xx | ||
else: | ||
y | ||
|
||
proc map*[T](self: Option[T], callback: proc (input: T)) = | ||
## Applies a callback to the value in this Option | ||
if self.isSome: | ||
|
@@ -163,7 +211,7 @@ proc flatMap*[A, B](self: Option[A], callback: proc (input: A): Option[B]): Opti | |
## Applies a callback to the value in this Option and returns an | ||
## option containing the new value. If this option is None, None will be | ||
## returned. Similar to ``map``, with the difference that the callback | ||
## returns an Option, not a raw value. This allows multiple procs with a | ||
## returns an Option, not a raw value. This allows multiple procedures with a | ||
## signature of ``A -> Option[B]`` (including A = B) to be chained together. | ||
map(self, callback).flatten() | ||
|
||
|
@@ -312,3 +360,48 @@ when isMainModule: | |
|
||
let noperson = none(Person) | ||
check($noperson == "None[Person]") | ||
|
||
test "logical operator()": | ||
let strings = ["a", "b", "c", "d", "e"] | ||
var sideEffects = 0 | ||
|
||
proc genSome(): Option[string] = | ||
result = some(strings[sideEffects]) | ||
sideEffects += 1 | ||
|
||
proc genNone(): Option[string] = | ||
result = none[string]() | ||
sideEffects += 1 | ||
|
||
proc genStr(): string = | ||
result = strings[sideEffects] | ||
sideEffects += 1 | ||
|
||
proc reset(): void = | ||
sideEffects = 0 | ||
|
||
# test ``or`` operator | ||
|
||
check((genNone() or genNone() or genNone()) == none[string]()) | ||
check(sideEffects == 3) | ||
reset() | ||
|
||
check((genNone() or genSome()) == some("b")) | ||
check(sideEffects == 2) | ||
reset() | ||
|
||
check((genNone() or genSome() or genSome()) == some("b")) | ||
check(sideEffects == 2) | ||
reset() | ||
|
||
check((genNone() or genSome() or genStr()) == "b") | ||
check(sideEffects == 2) | ||
reset() | ||
|
||
check((genNone() or genNone() or genStr()) == "c") | ||
check(sideEffects == 3) | ||
reset() | ||
|
||
check((genSome() or genNone() or genSome() or "c") == "a") | ||
check(sideEffects == 1) | ||
reset() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are not British, we use one space after a dot. (nitpick, I know)