__functor Override
Default behavior
Section titled “Default behavior”Every aspect has a default __functor that, when the aspect is called as a function, returns itself ignoring the context:
__functor = self: _context: self;This means when aspect A appears in another’s includes, resolution calls A { class, aspect-chain } which just returns A unchanged — so all of A’s class configs and nested includes get resolved normally.
Overriding __functor
Section titled “Overriding __functor”Replace __functor to intercept inclusion. The functor receives self (the attrset) and must return a function { class, aspect-chain } → aspect:
flake.aspects = { aspects, ... }: { adaptable = { nixos.base = true; __functor = self: { class, aspect-chain }: if class == "nixos" then self else { darwin.fallback = true; }; };};When resolved for "nixos", it returns the full aspect (with nixos.base = true).
When resolved for "darwin", it returns a different aspect with darwin.fallback = true.
Functor with parametric includes
Section titled “Functor with parametric includes”A common pattern: the functor intercepts includes to inject arguments before delegating:
flake.aspects = { aspects, ... }: { wrapper = { includes = [ aspects.tool ]; __functor = self: { includes = [ { classOne.bar = [ "from-functor" ]; } ] ++ map (f: f { message = "hello"; }) self.includes; }; }; tool = { message }: { classOne.bar = [ message ]; };};Here wrapper.__functor transforms each include by calling it with { message = "hello"; } before resolution.
Note: when __functor is overridden, the aspect’s own class configs (e.g., classOne.bar = [ "should-not-be-present" ])
are not automatically included — the functor’s return value replaces the aspect entirely during resolution.