diff --git a/Readme.md b/Readme.md index 460ab52..32e87e8 100644 --- a/Readme.md +++ b/Readme.md @@ -65,27 +65,29 @@ else: ### Option chaining -To safely access fields and call procs, you can use the `.?` operator: +To safely access fields and call procs, you can use the `?.` operator: + +> Note: before version 0.3.0, the operator was `.?` instead of `?.` ```nim var numbers: ?seq[int] var amount: ?int numbers = @[1, 2, 3].some -amount = numbers.?len +amount = numbers?.len # amount now holds the integer 3 numbers = seq[int].none -amount = numbers.?len +amount = numbers?.len # amount now equals int.none ``` -Invocations of the `.?` operator can be chained: +Invocations of the `?.` operator can be chained: ```nim import sequtils numbers = @[1, 1, 2, 2, 2].some -amount = numbers.?deduplicate.?len +amount = numbers?.deduplicate?.len # amount now holds the integer 2 ``` @@ -147,7 +149,7 @@ proc fails: ?!seq[int] = ### Binding, chaining, fallbacks and operators -Binding with the `=?` operator, chaining with the `.?` operator, fallbacks with +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 @@ -158,7 +160,7 @@ if x =? works(): # use x # chaining: -let amount = works().?deduplicate.?len +let amount = works()?.deduplicate?.len # fallback values: let value = fails() |? @[] diff --git a/questionable/chaining.nim b/questionable/chaining.nim index 809a36b..d14fcee 100644 --- a/questionable/chaining.nim +++ b/questionable/chaining.nim @@ -1,33 +1,33 @@ import std/macros -template `.?`*(option: typed, identifier: untyped{nkIdent}): untyped = +template `?.`*(option: typed, identifier: untyped{nkIdent}): untyped = option ->? option.unsafeGet.identifier -macro `.?`*(option: typed, infix: untyped{nkInfix}): untyped = +macro `?.`*(option: typed, infix: untyped{nkInfix}): untyped = let left = infix[1] - infix[1] = quote do: `option`.?`left` + infix[1] = quote do: `option`?.`left` infix -macro `.?`*(option: typed, bracket: untyped{nkBracketExpr}): untyped = +macro `?.`*(option: typed, bracket: untyped{nkBracketExpr}): untyped = let left = bracket[0] - bracket[0] = quote do: `option`.?`left` + bracket[0] = quote do: `option`?.`left` bracket -macro `.?`*(option: typed, dot: untyped{nkDotExpr}): untyped = +macro `?.`*(option: typed, dot: untyped{nkDotExpr}): untyped = let left = dot[0] - dot[0] = quote do: `option`.?`left` + dot[0] = quote do: `option`?.`left` dot -macro `.?`*(option: typed, call: untyped{nkCall}): untyped = +macro `?.`*(option: typed, call: untyped{nkCall}): untyped = let procedure = call[0] if call.len > 1: if procedure.kind == nnkDotExpr: let (inner, outer) = (procedure[0], procedure[1]) call[0] = outer - call.insert(1, quote do: `option`.?`inner`) + call.insert(1, quote do: `option`?.`inner`) call else: call.insert(1, quote do: `option`.unsafeGet) quote do: `option` ->? `call` else: - quote do: `option`.?`procedure` + quote do: `option`?.`procedure` diff --git a/testmodules/options/test.nim b/testmodules/options/test.nim index a3077bd..796d829 100644 --- a/testmodules/options/test.nim +++ b/testmodules/options/test.nim @@ -10,28 +10,28 @@ suite "optionals": check (?string is Option[string]) check (?seq[bool] is Option[seq[bool]]) - test ".? can be used for chaining optionals": + test "?. can be used for chaining optionals": let a: ?seq[int] = @[41, 42].some let b: ?seq[int] = seq[int].none - check a.?len == 2.some - check b.?len == int.none - check a.?len.?uint8 == 2'u8.some - check b.?len.?uint8 == uint8.none - check a.?len() == 2.some - check b.?len() == int.none - check a.?distribute(2).?len() == 2.some - check b.?distribute(2).?len() == int.none + check a?.len == 2.some + check b?.len == int.none + check a?.len?.uint8 == 2'u8.some + check b?.len?.uint8 == uint8.none + check a?.len() == 2.some + check b?.len() == int.none + check a?.distribute(2)?.len() == 2.some + check b?.distribute(2)?.len() == int.none - test ".? chain can be followed by . calls and operators": + test "?. chain can be followed by . calls and operators": let a = @[41, 42].some - check a.?len.get == 2 - check a.?len.get.uint8.uint64 == 2'u64 - check a.?len.get() == 2 - check a.?len.get().uint8.uint64 == 2'u64 - check a.?deduplicate()[0].?uint8.?uint64 == 41'u64.some - check a.?len + 1 == 3.some - check a.?deduplicate()[0] + 1 == 42.some - check a.?deduplicate.map(x => x) == @[41, 42].some + check a?.len.get == 2 + check a?.len.get.uint8.uint64 == 2'u64 + check a?.len.get() == 2 + check a?.len.get().uint8.uint64 == 2'u64 + check a?.deduplicate()[0]?.uint8?.uint64 == 41'u64.some + check a?.len + 1 == 3.some + check a?.deduplicate()[0] + 1 == 42.some + check a?.deduplicate.map(x => x) == @[41, 42].some test "[] can be used for indexing optionals": let a: ?seq[int] = @[1, 2, 3].some @@ -132,15 +132,15 @@ suite "optionals": var amount: ?int numbers = @[1, 2, 3].some - amount = numbers.?len + amount = numbers?.len check amount == 3.some numbers = seq[int].none - amount = numbers.?len + amount = numbers?.len check amount == int.none numbers = @[1, 1, 2, 2, 2].some - amount = numbers.?deduplicate.?len + amount = numbers?.deduplicate?.len check amount == 2.some # Fallback values diff --git a/testmodules/result/test.nim b/testmodules/result/test.nim index ecd4f32..c9bbbc8 100644 --- a/testmodules/result/test.nim +++ b/testmodules/result/test.nim @@ -14,28 +14,28 @@ suite "result": check (?!string is Result[string, ref CatchableError]) check (?!seq[bool] is Result[seq[bool], ref CatchableError]) - test ".? can be used for chaining results": + test "?. can be used for chaining results": let a: ?!seq[int] = @[41, 42].success let b: ?!seq[int] = seq[int].failure error - check a.?len == 2.success - check b.?len == int.failure error - check a.?len.?uint8 == 2'u8.success - check b.?len.?uint8 == uint8.failure error - check a.?len() == 2.success - check b.?len() == int.failure error - check a.?distribute(2).?len() == 2.success - check b.?distribute(2).?len() == int.failure error + check a?.len == 2.success + check b?.len == int.failure error + check a?.len?.uint8 == 2'u8.success + check b?.len?.uint8 == uint8.failure error + check a?.len() == 2.success + check b?.len() == int.failure error + check a?.distribute(2)?.len() == 2.success + check b?.distribute(2)?.len() == int.failure error - test ".? chain can be followed by . calls and operators": + test "?. chain can be followed by . calls and operators": let a = @[41, 42].success - check (a.?len.get == 2) - check (a.?len.get.uint8.uint64 == 2'u64) - check (a.?len.get() == 2) - check (a.?len.get().uint8.uint64 == 2'u64) - check (a.?deduplicate()[0].?uint8.?uint64 == 41'u64.success) - check (a.?len + 1 == 3.success) - check (a.?deduplicate()[0] + 1 == 42.success) - check (a.?deduplicate.map(x => x) == @[41, 42].success) + check (a?.len.get == 2) + check (a?.len.get.uint8.uint64 == 2'u64) + check (a?.len.get() == 2) + check (a?.len.get().uint8.uint64 == 2'u64) + check (a?.deduplicate()[0]?.uint8?.uint64 == 41'u64.success) + check (a?.len + 1 == 3.success) + check (a?.deduplicate()[0] + 1 == 42.success) + check (a?.deduplicate.map(x => x) == @[41, 42].success) test "[] can be used for indexing optionals": let a: ?!seq[int] = @[1, 2, 3].success @@ -130,7 +130,7 @@ suite "result": fail # chaining: - let amount = works().?deduplicate.?len + let amount = works()?.deduplicate?.len check (amount == 2.success) # fallback values: