[Nix-dev] Not understanding evaluation of with inside let

Harald van Dijk harald at gigawatt.nl
Mon May 16 10:34:49 CEST 2016


On 16/05/16 00:06, Vladimír Čunát wrote:
> It's the plain fact that `with` is "low-priority" in nix. Any identifier
> introduced by `with` is only used if it isn't found elsewhere.

Ah, thanks, and also to Layus for finding relevant code in Nix and 
giving a valid use case for it.

> I agree it can seem confusing, at least at first. I'm not sure if it's
> documented somewhere, but we've had quite a few discussions on that
> topic already.

I guess tests can sort of work as developer documentation, and I've now 
found that tests/lang/eval-okay-with.nix specifically tests this 
behaviour since 2010. Yet when it was first checked in in 2005, it 
tested the behaviour I would have expected. The commit message of the 
change to the test was simply "Doh." I was hoping to get a little bit 
more information there. :)

Documentation would be nice. Starting from what's documented now:

 > With-expressions

 > A with-expression,

 > with e1; e2

 > introduces the set e1 into the lexical scope of the expression e2.
 > For instance,

 > let as = { x = "foo"; y = "bar"; };
 > in with as; x + y

 > evaluates to "foobar" since the with adds the x and y attributes of
 > as to the lexical scope in the expression x + y. The most common use
 > of with is in conjunction with the import function. E.g.,

 > with (import ./definitions.nix); ...

 > makes all attributes defined in the file definitions.nix available as
 > if they were defined locally in a rec-expression.

I think the "as if they were defined locally in a rec-expression" is 
wrong. A rec-expression does not have this special low-priority scoping 
rule. Compare:

   let x = 1; in (rec { x = 2; y = x; }).y
   let x = 1; in with { x = 2; }; x

I think the documentation is saying these give the same result, but they 
don't.

It seems like your wording almost immediately gives a useful tweak and 
addition to this text:

   makes all attributes defined in the file definitions.nix available
   similarly to how a rec-expression would.

   However, the names introduced by with have lower priority than those
   introduced by other means. For instance,

   let as = { x = "foo"; y = "bar"; }; y = "baz";
   in with as; x + y

   evaluates to "foobaz".

Does this look okay?

Cheers,
Harald van Dijk


More information about the nix-dev mailing list