EffectsOf annotation

Rules 1-2 of the exception tracking inference rules (see the previous section) ensure the following works:

  1. proc weDontRaiseButMaybeTheCallback(callback: proc()) {.raises: [], effectsOf: callback.} =
  2. callback()
  3. proc doRaise() {.raises: [IOError].} =
  4. raise newException(IOError, "IO")
  5. proc use() {.raises: [].} =
  6. # doesn't compile! Can raise IOError!
  7. weDontRaiseButMaybeTheCallback(doRaise)

As can be seen from the example, a parameter of type proc (…) can be annotated as .effectsOf. Such a parameter allows for effect polymorphism: The proc weDontRaiseButMaybeTheCallback raises the exceptions that callback raises.

So in many cases a callback does not cause the compiler to be overly conservative in its effect analysis:

  1. {.push warningAsError[Effect]: on.}
  2. import algorithm
  3. type
  4. MyInt = distinct int
  5. var toSort = @[MyInt 1, MyInt 2, MyInt 3]
  6. proc cmpN(a, b: MyInt): int =
  7. cmp(a.int, b.int)
  8. proc harmless {.raises: [].} =
  9. toSort.sort cmpN
  10. proc cmpE(a, b: MyInt): int {.raises: [Exception].} =
  11. cmp(a.int, b.int)
  12. proc harmful {.raises: [].} =
  13. # does not compile, `sort` can now raise Exception
  14. toSort.sort cmpE