meta annotation request: sideEffects

I’d like a new class in the meta package, SideEffects, and a new top-level const instance of that class, sideEffects.

This fellow could be used to annotate a getter [1], indicating when a getter has side effects. Any static analysis rules (including lint rules), can then be written to “safely” assume that any property access or prefixed identifier has no side effects. I say “safely” because any time a confused developer sees a static analysis report and says “oh that’s not right at all,” they can add this @sideEffects annotation to a getter, which the rule can use to not generate false positive reports.

For example:

class A {
  @sideEffects
  B get b {
    print('b was gotten');
    return B();
  }
}

class B {
  int c, d;
}

void f() {
  if (a.b.c == null) {
    a.b.c = 7; // triggers a prefer_conditional_assignment lint report.
  }

  a.b
      ..c = 1
      ..d = 2;
  a.b.c = 3; // triggers a cascade_invocations lint report.

  a.b; // triggers unnecessary_statement lint report.

  a.b.c = 7;
  return a.b.c; // triggers a join_return_with_assignment lint report.
}

Each of these four lint reports are incorrect, as get A.b has side effects. We’ve seen real code in, e.g. caching modules that have to ignore these reports.

[1] why just a getter? Meh, I’d be happy to open this up to more node types, but I’ve only thought of uses for getters for now.

Author: Fantashit

1 thought on “meta annotation request: sideEffects

  1. When we looked at getters across google3 in the context of unnecessary_statements, we did find getters with side effects, but almost exclusively that side effect was to do with loading or caching, i.e. not visible to the caller.

    The obvious question is, if the side effects are not visible, why would you want to trigger just the side effect in a way which would trigger a lint? The answer, which we did see in practice, is for precaching/loading, testing and benchmarking.

    As Sam mentions there is a general feeling that to get the most value from lints we should have it be possible to have them be enforced 100%% without needing ignore.

    At first glance I don’t think @sideEffects is quite right for that; I think that it’s usually a property of the caller that a getter is being used just for the side effect–as mentioned, for precaching, testing or benchmarking.

    So how about a justForSideEffects method, similar to unawaited, which would live in package:pedantic? That would be enough to silence unnecessary_statements, not sure about the others.

Comments are closed.