[Nix-dev] Re: [Nix-commits] SVN commit: nix - 15553 - eelco - nix/trunk/src/libexpr

Eelco Dolstra e.dolstra at tudelft.nl
Tue May 12 13:25:34 CEST 2009


Nicolas Pierron wrote:

> I just want to warn you that NixOS should not compile anymore because
> it relies on:
> - attribute set comparison.
> - function comparison.

Yes, I added the check to find all places in Nixpkgs and NixOS that rely on the
undefined behaviour in the evaluator so that we can fix them.  For instance, it
turns out that there some places in Nixpkgs where the uniqList function is
applied to a list of attrsets, so it's basically just lucky that it worked at
all ;-)

I've now made the check conditional on an environment variable
(NIX_NO_UNSAFE_EQ).  It's disabled by default (i.e. everything continues to
work).  This can be removed once we've fixed all attrset equality tests.

> To fix this I think we need an operator to verify the "same source as"
> relation which is used by NixOS which should behave as commented on
> the following examples:
> 
> let
>   a = { x = 1; };
>   b = a;
>   c = (import ./foo) {};
>   d = (import ./foo) {};
>   e = (import ./foo) { pkgs = ./nixpkgs; };
> in (sameSourceAs a a) == true
> && (sameSourceAs b a) == (sameSourceAs a b)
> && (sameSourceAs c d) == true
> && (sameSourceAs c e) == false

What does "source" mean?  That a value comes from a certain source file?  Or is
it pointer equality?  In any case it seems difficult to come up with a clean
semantics.

> This type of comparison is used in NixOS to avoid circular imports of
> option sets.  It is hidden inside the "uniqFlatten" function which
> call the "elem" function.

This is for "require", right?  There are a few solutions:

- (Quick solution)  Get rid of require, and just make sure that every NixOS
module is included somewhere, say in system/options.nix.

- Make "require" a list of filenames rather than a list of (usually) imports.
Then the option handling code knows which modules it has already processed.

- Give NixOS modules an explicit name, i.e. a module name:

  {pkgs, config, ...}:

  { name = "cron";
    requires =
      [ (import ./upstart.nix)
        ...
      ];
  };

  The name allows the option handling code to know which modules it has already
processed.

Really, the fundamental problem is that we're doing a graph traversal here (over
the graph of option "requires"), and in a graph traversal you need a notion of
node identity to know which nodes you've already visited.  In purely functional
languages you can't use pointer equality for this, so you need to give nodes an
explicit identity.

-- 
Eelco Dolstra | http://www.st.ewi.tudelft.nl/~dolstra/



More information about the nix-dev mailing list