Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/codex-storage/questionable
Elegant optional types for Nim
https://github.com/codex-storage/questionable
Last synced: 3 months ago
JSON representation
Elegant optional types for Nim
- Host: GitHub
- URL: https://github.com/codex-storage/questionable
- Owner: codex-storage
- License: other
- Created: 2021-03-05T20:08:23.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2024-04-20T06:08:53.000Z (7 months ago)
- Last Synced: 2024-05-29T01:54:49.357Z (5 months ago)
- Language: Nim
- Homepage:
- Size: 111 KB
- Stars: 114
- Watchers: 43
- Forks: 4
- Open Issues: 1
-
Metadata Files:
- Readme: Readme.md
- License: License.md
Awesome Lists containing this project
- awesome-nim - questionable - Elegant optional types for Nim. (Language Features / Error Handling)
README
Questionable 🤔
==============[Option][1] and [Result][2] are two powerful abstractions that can be used
instead of raising errors. They can be a bit unwieldy though. This library is an
attempt at making their use a bit more elegant.Installation
------------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.15 & < 0.11.0"
```If you want to make use of Result types, then you also have to add either the
[result][2] package, or the [stew][4] package:```nim
requires "results" # either this
requires "stew" # or this
```Options
-------You can use `?` to make a type optional. For example, the type `?int` is just
short for [`Option[int]`][1].```nim
import questionablevar x: ?int
```Assigning values is done using the `some` and `none` procs from the standard library:
```nim
x = 42.some # Option x now holds the value 42
x = int.none # Option x no longer holds a value
```
### Option bindingThe `=?` operator lets you bind the value inside an Option to a new variable. It
can be used inside of a conditional expression, for instance in an `if`
statement:```nim
x = 42.someif y =? x:
# y equals 42 here
else:
# this is never reachedx = int.none
if y =? x:
# this is never reached
else:
# this is reached, and y is not defined
```The `without` statement can be used to place guards that ensure that an Option
contains a value:```nim
proc someProc(option: ?int) =
without value =? option:
# option did not contain a value
return# use value
```### Option chaining
To safely access fields and call procs, you can use the `.?` operator:
> Note: in versions 0.3.x and 0.4.x, the operator was `?.` instead of `.?`
```nim
var numbers: ?seq[int]
var amount: ?intnumbers = @[1, 2, 3].some
amount = numbers.?len
# amount now holds the integer 3numbers = seq[int].none
amount = numbers.?len
# amount now equals int.none
```Invocations of the `.?` operator can be chained:
```nim
import sequtilsnumbers = @[1, 1, 2, 2, 2].some
amount = numbers.?deduplicate.?len
# amount now holds the integer 2
```### Fallback values
Use the `|?` operator to supply a fallback value when the Option does not hold
a value:```nim
x = int.nonelet z = x |? 3
# z equals 3
```### Obtaining value with !
The `!` operator returns the value of an Option when you're absolutely sure that
it contains a value.```nim
x = 42.some
let dare = !x # dare equals 42x = int.none
let crash = !x # raises a Defect
```### Operators
The operators `[]`, `-`, `+`, `@`, `*`, `/`, `div`, `mod`, `shl`, `shr`, `&`,
`<=`, `<`, `>=`, `>` are all lifted, so they can be used directly on Options:```nim
numbers = @[1, 2, 3].some
x = 39.somelet indexed = numbers[0] # equals 1.some
let sum = x + 3 # equals 42.some
```Results
-------Support for `Result` is considered experimental. If you want to use them you
have to explicitly import the `questionable/results` module:```nim
import questionable/results
```You can use `?!` 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]`.```nim
proc example: ?!int =
# either return an integer or an error
```Results can be made using the `success` and `failure` procs:
```nim
proc works: ?!seq[int] =
# always returns a Result holding a sequence
success @[1, 1, 2, 2, 2]proc fails: ?!seq[int] =
# always returns a Result holding an error
failure "something went wrong"
```### Binding, chaining, fallbacks and operators
Binding with the `=?` operator, chaining with the `.?` operator, fallbacks with
the `|?` operator, and all the other operators that work with Options also work
for Results:
```nim
import sequtils# binding:
if x =? works():
# use x# chaining:
let amount = works().?deduplicate.?len# fallback values:
let value = fails() |? @[]# lifted operators:
let sum = works()[3] + 40
```### Without statement
The `without` statement can also be used with Results. It provides access to any
errors that may arise:```nim
proc someProc(r: ?!int) =
without value =? r, error:
# use `error` to get the error from r
return# use value
```### Catching errors
When you want to use Results, but need to call a proc that may raise an
error, you can use `catch`:```nim
import strutilslet x = parseInt("42").catch # equals 42.success
let y = parseInt("XX").catch # equals int.failure(..)
```### Conversion to Option
Any Result can be converted to an Option:
```nim
let converted = works().option # equals @[1, 1, 2, 2, 2].some
```[1]: https://nim-lang.org/docs/options.html
[2]: https://github.com/arnetheduck/nim-result
[3]: https://github.com/nim-lang/nimble
[4]: https://github.com/status-im/nim-stew