oppiliappan / statix

lints and suggestions for the nix programming language
https://git.peppe.rs/languages/statix/about
MIT License
552 stars 21 forks source link

Warn when inheriting attributes from a function call #55

Open ilkecan opened 1 year ago

ilkecan commented 1 year ago

It is possible to inherit attributes from another set^1. For example:

let
  x = { a = 1; b = 2; }
  y = { inherit (x) a b; }
in
y # evaluates to `{ a = 1; b = 2; }`

But since Nix does not have maximal laziness, inheriting from the result of a function call will evaluate the function for each inherited attribute. That is, evaluating the expression below:

let
  f = x:
    builtins.trace "evaluated" {
      a = x + 1;
      b = x + 2;
    };
  inherit (f 0) a b;
in
[ a b ]

will evaluate f 0 2 times (which can be checked with trace). This can be avoided with:

let
  f = x:
    builtins.trace "evaluated" {
      a = x + 1;
      b = x + 2;
    };
  set = f 0;
  inherit (set) a b;
in
[ a b ]

In this case f 0 will be evaluated only once because the result is saved in a variable.


An exception to this is import. While the manual notes that import is a regular function, result of import <path> seems to be cached internally, so:

let
  inherit (import <path>) f g;            # this is OK
  inherit (import <path> <some-args>) f g # this is not OK 
in
oppiliappan commented 1 year ago

aha, this is a very nice lint idea, thanks!