Tag tracking

Exception tracking is part of Nim’s effect system. Raising an exception is an effect. Other effects can also be defined. A user defined effect is a means to tag a routine and to perform checks against this tag:

  1. type IO = object ## input/output effect
  2. proc readLine(): string {.tags: [IO].} = discard
  3. proc no_effects_please() {.tags: [].} =
  4. # the compiler prevents this:
  5. let x = readLine()

A tag has to be a type name. A tags list - like a raises list - can also be attached to a proc type. This affects type compatibility.

The inference for tag tracking is analogous to the inference for exception tracking.

There is also a way which can be used to forbid certain effects:

  1. type IO = object ## input/output effect
  2. proc readLine(): string {.tags: [IO].} = discard
  3. proc echoLine(): void = discard
  4. proc no_IO_please() {.forbids: [IO].} =
  5. # this is OK because it didn't define any tag:
  6. echoLine()
  7. # the compiler prevents this:
  8. let y = readLine()

The forbids pragma defines a list of illegal effects - if any statement invokes any of those effects, the compilation will fail. Procedure types with any disallowed effect are the subtypes of equal procedure types without such lists:

  1. type MyEffect = object
  2. type ProcType1 = proc (i: int): void {.forbids: [MyEffect].}
  3. type ProcType2 = proc (i: int): void
  4. proc caller1(p: ProcType1): void = p(1)
  5. proc caller2(p: ProcType2): void = p(1)
  6. proc effectful(i: int): void {.tags: [MyEffect].} = echo $i
  7. proc effectless(i: int): void {.forbids: [MyEffect].} = echo $i
  8. proc toBeCalled1(i: int): void = effectful(i)
  9. proc toBeCalled2(i: int): void = effectless(i)
  10. ## this will fail because toBeCalled1 uses MyEffect which was forbidden by ProcType1:
  11. caller1(toBeCalled1)
  12. ## this is OK because both toBeCalled2 and ProcType1 have the same requirements:
  13. caller1(toBeCalled2)
  14. ## these are OK because ProcType2 doesn't have any effect requirement:
  15. caller2(toBeCalled1)
  16. caller2(toBeCalled2)

ProcType2 is a subtype of ProcType1. Unlike with the tags pragma, the parent context - the function which calls other functions with forbidden effects - doesn’t inherit the forbidden list of effects.