Skip to content

Commit

Permalink
unionOfDisjoint: use builtins.intersectAttrs
Browse files Browse the repository at this point in the history
This brings two benefits:

1. The complete list of collisions is printed in the whenever any colliding
   attribute is accessed.

2. The sets are intersected using a C++ primitive, which runs in O(n) time
   (intersecting pre-sorted lists) with small constants rather than interpreted
   Nix code.

Thanks to @toonn for prompting this improvement.
  • Loading branch information
Adam Joseph committed Sep 25, 2022
1 parent 99da193 commit 037cf2f
Showing 1 changed file with 8 additions and 5 deletions.
13 changes: 8 additions & 5 deletions lib/attrsets.nix
Original file line number Diff line number Diff line change
Expand Up @@ -627,11 +627,14 @@ rec {
`y`, and all values `assert` with an error message. This
operator is commutative, unlike (//). */
unionOfDisjoint = x: y:
x // (mapAttrs
(name: val:
if hasAttr name x
then builtins.throw "attribute collision: ${name}"
else val) y);
let
intersection = builtins.intersectAttrs x y;
collisions = lib.concatStringsSep " " (builtins.attrNames intersection);
mask = builtins.mapAttrs (name: value: builtins.throw
"unionOfDisjoint: collision on ${name}; complete list: ${collisions}")
intersection;
in
(x // y) // mask;

/*** deprecated stuff ***/

Expand Down

0 comments on commit 037cf2f

Please sign in to comment.