Source Edit

This module allows evaluating expressions safely against the following conditions:

  • nil dereferences
  • field accesses with incorrect discriminant in case objects

default(T) is returned in those cases when evaluating an expression of type T. This simplifies code by reducing need for if-else branches.

Note: experimental module, unstable API.

Example:

  1. import std/wrapnils
  2. type Foo = ref object
  3. x1: string
  4. x2: Foo
  5. x3: ref int
  6. var f: Foo
  7. assert ?.f.x2.x1 == "" # returns default value since `f` is nil
  8. var f2 = Foo(x1: "a")
  9. f2.x2 = f2
  10. assert ?.f2.x1 == "a" # same as f2.x1 (no nil LHS in this chain)
  11. assert ?.Foo(x1: "a").x1 == "a" # can use constructor inside
  12. # when you know a sub-expression doesn't involve a `nil` (e.g. `f2.x2.x2`),
  13. # you can scope it as follows:
  14. assert ?.(f2.x2.x2).x3[] == 0
  15. assert (?.f2.x2.x2).x3 == nil # this terminates ?. early

Example:

  1. import std/wrapnils
  2. # ?. also allows case object
  3. type B = object
  4. b0: int
  5. case cond: bool
  6. of false: discard
  7. of true:
  8. b1: float
  9. var b = B(cond: false, b0: 3)
  10. doAssertRaises(FieldDefect): discard b.b1 # wrong discriminant
  11. doAssert ?.b.b1 == 0.0 # safe
  12. b = B(cond: true, b1: 4.5)
  13. doAssert ?.b.b1 == 4.5
  14. # lvalue semantics are preserved:
  15. if (let p = ?.b.b1.addr; p != nil): p[] = 4.7
  16. doAssert b.b1 == 4.7

Imports

macros, options

Procs

  1. func `[]`[T, I](a: Option[T]; i: I): auto {.inline.}

See top-level example. Source Edit

  1. func `[]`[U](a: Option[U]): auto {.inline.}

See top-level example. Source Edit

Macros

  1. macro `?.`(a: typed): auto

Transforms a into an expression that can be safely evaluated even in presence of intermediate nil pointers/references, in which case a default value is produced. Source Edit

  1. macro `??.`(a: typed): Option

Same as ?. but returns an Option.

Example:

  1. import std/options
  2. type Foo = ref object
  3. x1: ref int
  4. x2: int
  5. # `?.` can't distinguish between a valid vs invalid default value, but `??.` can:
  6. var f1 = Foo(x1: int.new, x2: 2)
  7. doAssert (??.f1.x1[]).get == 0 # not enough to tell when the chain was valid.
  8. doAssert (??.f1.x1[]).isSome # a nil didn't occur in the chain
  9. doAssert (??.f1.x2).get == 2
  10. var f2: Foo
  11. doAssert not (??.f2.x1[]).isSome # f2 was nil
  12. doAssertRaises(UnpackDefect): discard (??.f2.x1[]).get
  13. doAssert ?.f2.x1[] == 0 # in contrast, this returns default(int)

Source Edit

Templates

  1. template fakeDot(a: Option; b): untyped

See top-level example. Source Edit