Compare commits

...

7 Commits

Author SHA1 Message Date
Adam Uhlíř
2906828765
Add errorOption example to Readme
Added example for errorOption conversion in Readme.
2025-10-22 16:12:58 +02:00
Marcin Czenko
2e7f20392b Update Readme.md
Missing "to"
2024-12-04 01:01:47 +01:00
Mark Spanbroek
3dcf21491d without with error variable works for any Result type 2024-05-29 12:45:40 +02:00
Mark Spanbroek
82d90b67bc version 0.10.15 2024-04-20 08:08:31 +02:00
Mark Spanbroek
b098ae696a Workaround for Nim gensym bug
Occasionally different `evaluated` symbols would be
gensymmed to the same symbol.
2024-04-20 08:07:28 +02:00
Mark Spanbroek
83ae4a6409 version 0.10.14 2024-03-10 12:14:59 +01:00
Mark Spanbroek
57e467b8b0 Fix: without should work when $ has side effects
It's ok to use unsafeError in bindFailed, because we've
already checked that the result contains an error.
2024-03-10 12:13:25 +01:00
5 changed files with 49 additions and 11 deletions

View File

@ -12,7 +12,7 @@ Use the [Nimble][3] package manager to add `questionable` to an existing
project. Add the following to its .nimble file:
```nim
requires "questionable >= 0.10.13 & < 0.11.0"
requires "questionable >= 0.10.15 & < 0.11.0"
```
If you want to make use of Result types, then you also have to add either the
@ -151,7 +151,7 @@ have to explicitly import the `questionable/results` module:
import questionable/results
```
You can use `?!` make a Result type. These Result types either hold a value or
You can use `?!` to make a Result type. These Result types either hold a value or
an error. For example the type `?!int` is short for `Result[int, ref
CatchableError]`.
@ -226,6 +226,7 @@ Any Result can be converted to an Option:
```nim
let converted = works().option # equals @[1, 1, 2, 2, 2].some
let errOption = fails().errorOption # option that is set when the Result holds an error
```
[1]: https://nim-lang.org/docs/options.html

View File

@ -1,4 +1,4 @@
version = "0.10.13"
version = "0.10.15"
author = "Questionable Authors"
description = "Elegant optional types"
license = "MIT"

View File

@ -11,26 +11,28 @@ macro captureBindError*(error: var ref CatchableError, expression): auto =
# name of the error variable as a string literal
let errorVariableName = newLit($error)
let evaluated = genSym(nskLet, "evaluated")
quote do:
# add error variable to the top of the stack
static: errorVariableNames.add(`errorVariableName`)
# evaluate the expression
let evaluated = `expression`
let `evaluated` = `expression`
# pop error variable from the stack
static: discard errorVariableNames.pop()
# return the evaluated result
evaluated
`evaluated`
func error[T](_: Option[T]): ref CatchableError =
func unsafeCatchableError[T](_: Option[T]): ref CatchableError =
newException(ValueError, "Option is set to `none`")
func error[T](_: ref T): ref CatchableError =
func unsafeCatchableError[T](_: ref T): ref CatchableError =
newException(ValueError, "ref is nil")
func error[T](_: ptr T): ref CatchableError =
func unsafeCatchableError[T](_: ptr T): ref CatchableError =
newException(ValueError, "ptr is nil")
func error[Proc: proc | iterator](_: Proc): ref CatchableError =
func unsafeCatchableError[Proc: proc | iterator](_: Proc): ref CatchableError =
newException(ValueError, "proc or iterator is nil")
macro bindFailed*(expression: typed) =
@ -49,4 +51,4 @@ macro bindFailed*(expression: typed) =
# check that the error variable is in scope
when compiles(`errorVariable`):
# assign bind error to error variable
`errorVariable` = `expression`.error
`errorVariable` = `expression`.unsafeCatchableError

View File

@ -123,6 +123,18 @@ template toOption*[T, E](value: Result[T, E]): ?T =
value.option
proc unsafeCatchableError*[T, E](value: Result[T, E]): ref CatchableError =
## Returns the error from the Result, converted to `ref CatchableError` if
## necessary. Behaviour is undefined when the result holds a value instead of
## an error.
when E is ref CatchableError:
value.unsafeError
else:
when compiles($value.unsafeError):
newException(ResultFailure, $value.unsafeError)
else:
newException(ResultFailure, "Result is an error")
proc errorOption*[T, E](value: Result[T, E]): ?E =
## Returns an Option that contains the error from the Result, if it has one.

View File

@ -643,6 +643,19 @@ suite "result":
someProc(42.success)
someProc(int.failure "some error")
type TypeWithSideEffect = object
proc `$`*(value: TypeWithSideEffect): string {.sideEffect.} =
discard
suite "result side effects":
test "without statement with error works when `$` has side effects":
proc foo =
without x =? TypeWithSideEffect.failure("error"), error:
discard error
return
fail()
foo()
import pkg/questionable/resultsbase
@ -650,7 +663,7 @@ suite "result compatibility":
type R = Result[int, string]
let good = R.ok 42
let bad = R.err "error"
let bad = R.err "some error"
test "|?, =? and .option work on other types of Result":
check bad |? 43 == 43
@ -668,3 +681,13 @@ suite "result compatibility":
fail
without b =? good:
fail
test "without statement with error works on other type of Result":
without value =? bad, error:
check error of ResultFailure
check error.msg == "some error"
test "without statement with error works on Result[T, void]":
without value =? Result[int, void].err, error:
check error of ResultFailure
check error.msg == "Result is an error"