[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