# ELI5 how finalAttrs design pattern works

Please, explain like I am 5 years old how that `finalAttrs: {}` design pattern works in tandem with `stdenv.mkDerivation`.

And, possibly, how can it be adapted to work with other frameworks (like, say, `buildGoModule`).

I was playing with nix repl:

``````> fun = finalAttrs: { a=1; b = finalAttrs.a+1; c = finalAttrs.b+2;  }

> fun { a=0; }

nix-repl> fun ( { a = 0; })
{ a = 1; b = 1; c = error: attribute 'b' missing

at «string»:1:45:

1|  finalAttrs: { a=1; b = finalAttrs.a+1; c = finalAttrs.b+2;  }
|                                             ^
Did you mean a?

nix-repl> fun (fun { a = 0; })
{ a = 1; b = 2; c = 3; }

nix-repl>
``````

However it didn’t help me too much.

2 Likes

It’s more like this:

``````> fun = finalAttrs: { a=1; b = finalAttrs.a+1; c = finalAttrs.b+2;  }

> fix = f: let x = f x; in x

> fix fun
{ a = 1; b = 2; c = 4; }
``````

The magic is that `fix` function. It calls a function with its own result as the argument (that’s what `let x = f x` does). This is possible because of laziness. So `fun` returns `{ a = 1;, b = <thunk>; c = <thunk>; }`. If you evaluate `b`, then it’ll evaluate `finalAttrs.a + 1`, which means reaching into the attrset that was already returned and pulling out `a`, which is already `1`.

That version of `fix` is efficient, but it’s functionally equivalent to this:

``````fix = f: f (fix f)
``````

So maybe you can see how this relates to your observation about `fun (fun { a = 0; })`, in that it takes it to the extreme and evaluates to infinitely re-apply `fun` to itself in that manner.

5 Likes