Skip to content

Commit

Permalink
maybe => nilwrap
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheecour committed Jan 5, 2020
1 parent 950ef81 commit 0e4bcfa
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 24 deletions.
4 changes: 4 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
- Added `sugar.capture` for capturing some local loop variables when creating a closure.
This is an enhanced version of `closureScope`.

- Added `nilwraps.nilwrap` for chains of field-access and indexing where the LHS can be nil.
This simplifies code by reducing need for if-else branches around intermediate maybe nil values.
Eg: `echo n.nilwrap.typ.kind[]`

## Library changes

- `asyncdispatch.drain` now properly takes into account `selector.hasPendingOperations`
Expand Down
30 changes: 15 additions & 15 deletions lib/std/maybes.nim → lib/std/nilwraps.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
type Maybe*[T] = object
type Nilwrap*[T] = object
valueImpl*: T

proc maybe*[T](a: T): auto =
proc nilwrap*[T](a: T): auto =
## Allows chains of field-access and indexing where the LHS can be nil.
## This simplifies code by reducing need for if-else branches around intermediate
## maybe nil values.
Expand All @@ -10,32 +10,32 @@ proc maybe*[T](a: T): auto =
x1: string
x2: Foo
var f: Foo
assert f.maybe.x2.x1[] == ""
Maybe[T](valueImpl: a)
assert f.nilwrap.x2.x1[] == ""
Nilwrap[T](valueImpl: a)

{.push experimental: "dotOperators".}

template `.`*(a: Maybe, b): untyped =
## See `maybe`
template `.`*(a: Nilwrap, b): untyped =
## See `nilwrap`
let a2 = a.valueImpl # to avoid double evaluations
when type(a2) is ref|ptr:
if a2 == nil:
maybe(default(type(a2.b)))
nilwrap(default(type(a2.b)))
else:
maybe(a2.b)
nilwrap(a2.b)
else:
maybe(a2.b)
nilwrap(a2.b)

{.pop.}

template `[]`*(a: Maybe): untyped =
## See `maybe`
template `[]`*(a: Nilwrap): untyped =
## See `nilwrap`
a.valueImpl

template `[]`*[I](a: Maybe, i: I): untyped =
## See `maybe`
template `[]`*[I](a: Nilwrap, i: I): untyped =
## See `nilwrap`
let a2 = a.valueImpl # to avoid double evaluations
if len(a2) == 0:
maybe(default(type(a2[i])))
nilwrap(default(type(a2[i])))
else:
maybe(a2[i])
nilwrap(a2[i])
18 changes: 9 additions & 9 deletions tests/stdlib/tmaybes.nim → tests/stdlib/tnilwraps.nim
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import std/maybes
import std/nilwraps

proc main() =
type Bar = object
Expand All @@ -20,17 +20,17 @@ proc main() =
witness.inc
result = Foo(x1: x1)

doAssert a.maybe.x2.x2.x1[] == 0.0
doAssert a3.maybe.x2.x2.x1[] == 1.2
doAssert a3.maybe.x2.x2.x5.len[] == 0
doAssert a3.maybe.x2.x2.x3.len[] == 3
doAssert a3.maybe.x2.x2.x3.len == maybe(3)
doAssert a3.maybe.x2.x2.x3[1][] == 'b'
doAssert a.maybe.x2.x2.x3[1][] == default(char)
doAssert a.nilwrap.x2.x2.x1[] == 0.0
doAssert a3.nilwrap.x2.x2.x1[] == 1.2
doAssert a3.nilwrap.x2.x2.x5.len[] == 0
doAssert a3.nilwrap.x2.x2.x3.len[] == 3
doAssert a3.nilwrap.x2.x2.x3.len == nilwrap(3)
doAssert a3.nilwrap.x2.x2.x3[1][] == 'b'
doAssert a.nilwrap.x2.x2.x3[1][] == default(char)

# make sure no double evaluation bug
doAssert witness == 0
doAssert initFoo(1.3).maybe.x1[] == 1.3
doAssert initFoo(1.3).nilwrap.x1[] == 1.3
doAssert witness == 1

main()

0 comments on commit 0e4bcfa

Please sign in to comment.