`without` statement

This commit is contained in:
Mark Spanbroek 2021-04-16 12:27:17 +02:00
parent 827214f7a9
commit ef5f796463
6 changed files with 71 additions and 0 deletions

View File

@ -63,6 +63,18 @@ else:
# this is reached, and y is not defined
```
The `without` statement can be used to place guards that ensure that an optional
contains a value:
```nim
proc someProc(option: ?int) =
without value =? option:
# option did not contain a value
return
# use value
```
When using `=?` in generic code you may face errors about undeclared
identifiers. This is a limitation of Nim and can be worked around with a `mixin`
statement:

View File

@ -3,12 +3,14 @@ import std/macros
import ./chaining
import ./indexing
import ./operators
import ./without
include ./errorban
export options
export chaining
export indexing
export without
template `?`*(T: typed): type Option[T] =
Option[T]

View File

@ -4,12 +4,14 @@ import ./options
import ./chaining
import ./indexing
import ./operators
import ./without
include ./errorban
export resultsbase except ok, err, isOk, isErr
export chaining
export indexing
export without
type ResultFailure* = object of CatchableError

4
questionable/without.nim Normal file
View File

@ -0,0 +1,4 @@
template without*(expression, body) =
let ok = expression
if not ok:
body

View File

@ -116,6 +116,30 @@ suite "optionals":
check 42.some.toString == "42"
check int.none.toString == "none"
test "without statement can be used for early returns":
proc test1 =
without a =? 42.some:
fail
return
check a == 42
proc test2 =
without a =? int.none:
return
fail
test1()
test2()
test "without statement evaluates optional expression only once":
proc test =
var count = 0
without a =? (inc count; 42.some):
discard
check count == 1
test()
test ".?[] can be used for indexing tables without raising KeyError":
let table = @{"a": 1, "b": 2}.toTable
check table.?["a"] == 1.some
@ -194,6 +218,18 @@ suite "optionals":
else:
check not compiles(y)
# without statement
proc someProc(option: ?int) =
without value =? option:
check option.isNone
return
check value == 42
someProc(int.none)
someProc(42.some)
# Option chaining
var numbers: ?seq[int]

View File

@ -108,6 +108,21 @@ suite "result":
let b {.used.} = a
check count == 1
test "without statement works for results":
proc test1 =
without a =? 42.success:
fail
return
check a == 42
proc test2 =
without a =? int.failure "error":
return
fail
test1()
test2()
test "catch can be used to convert exceptions to results":
check parseInt("42").catch == 42.success
check parseInt("foo").catch.error of ValueError