Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inconsistent and buggy behavior of argument sets with aliases #745

Closed
anderspapitto opened this issue Dec 18, 2015 · 11 comments
Closed

inconsistent and buggy behavior of argument sets with aliases #745

anderspapitto opened this issue Dec 18, 2015 · 11 comments

Comments

@anderspapitto
Copy link

I'm trying to figure out the semantics of aliases (@-bindings) and they look pretty broken. In particular, I expect

let a = b.c; in a

to always be equivalent to

let a = with b; c; in a

but, it's not. here are some examples

$ nix-repl 
Welcome to Nix version 1.10. Type :? for help.

nix-repl> f1 = args@{ a ? 123 } : args.a

nix-repl> f1 { }
error: attribute ‘a’ missing, at (string):1:21

nix-repl> f2 = args@{ a ? 123 } : a

nix-repl> f2 { }
123

nix-repl> f3 = args@{ a ? 123 } : with args; a

nix-repl> f3 { }
123

nix-repl> f4 = args@{ a ? args, b ? 234 } : args

nix-repl> f4 { }
{ }

nix-repl> f5 = args@{ a ? args, b ? 234 } : args.a

nix-repl> f5 { }
error: attribute ‘a’ missing, at (string):1:31

nix-repl> f6 = args@{ a ? args, b ? 234 } : with args; a

nix-repl> f6 { }
{ }

nix-repl> f7 = args@{ a ? args, b ? 234 } : with args; with a; a

nix-repl> f7 { }
{ }

nix-repl> f8 = args@{ a ? args, b ? 234 } : with args; b

nix-repl> f8 { }
234
@vcunat
Copy link
Member

vcunat commented Dec 18, 2015

The state AFAIK:

  • @-pattern binds the argument exactly as it was passed, i.e. no defaults are substituted (yet).
  • with has reversed order of preference (when comparing to what I consider traditional semantics), e.g. when you have a binding available from two places, the one introduced by with is not preferred. (I don't remember the exact semantics.)

I've been burned by some of these, but they don't seem inconsistent or buggy to me, perhaps just non-intuitive. It's arguably rather hard to change semantics at this point. Another of my personal examples: #629.

@fkz
Copy link
Contributor

fkz commented Dec 20, 2015

After playing a little bit with it, I found that

  • with overrides a previous with
  • let overrides a previous let
  • let-introduced names take always precedence to with-introduced names
  • @-patterns are like let introductions in this regard

I think, these rules make sense: If there's a name defined somewhere with a let, you can be sure that this is used and not silently overridden by a with (maybe because the definition of the expression changed); also from an efficiency standpoint that's probably good.

But we should really document them better in the manual, I haven't found these rules there.

@anderspapitto
Copy link
Author

hmm. maybe these are ok. How about this one, though? Setting a defaulted value to the default value changes behavior

$ nix-repl 
Welcome to Nix version 1.10. Type :? for help.

nix-repl> g1 = x: x.a

nix-repl> h1 = args@{ a ? 123 } : g1 args

nix-repl> h1 { }
error: attribute ‘a’ missing, at (string):1:5

nix-repl> h1 { a = 123; }
123

@vcunat
Copy link
Member

vcunat commented Dec 20, 2015

@-pattern binds the argument exactly as it was passed, i.e. no defaults are substituted (yet).

@vcunat
Copy link
Member

vcunat commented Dec 20, 2015

Perhaps it's good to view these as patterns that only create bindings, without changing or creating any values.

@fkz
Copy link
Contributor

fkz commented Dec 20, 2015

Yeah, so I think arg@{ p1 ? v1, p2 ? v2, ..., pn ? vn }: body is nearly equivalent (it's not at least becase of builtins.functionArgs) to

arg: 
let p1 = if arg ? p1 then arg.p1 else v1; 
    p2 = if arg ? p2 then arg.p2 else v2;
    ...
    pn = if arg ? pn then arg.pn else vn;
in body

@vcunat
Copy link
Member

vcunat commented Dec 21, 2015

BTW, @edolstra: is it intentional that builtins.functionArgs is undocumented (in nix manual's builtins list)?

@edolstra
Copy link
Member

@vcunat No, I don't think so.

@Profpatsch
Copy link
Member

I just noticed the wonky (and undocumented!) semantics of with, too.

let vuizvui = "foo"; bar.vuizvui = "bar"; in  with bar; vuizvui

will output "foo" instead of bar. I don’t see any way this could be intended behaviour, because that would semantically mean not all defined symbols are created equal (and you definitely cannot know without knowing exactly how they were defined).

The above is of course a reduced example from the real life situation where I was surprised by this, which looked a bit like this:

config = {
  vuizvui.someoption = true; # in config

  environment.systemPackages = with pkgs; let
    somePackages = [
       … /* a lot of packages */
       vuizvui.somepackage # in pkgs
    ];
    in somePackages ++ …;
}

This blows up because nix tries to find somepackge in config.vuizvui.
Bear in mind that without some vuizvui config options already defined I would have had no lexical hint whatsoever that this could be a name clash. That is very bad.

I’m aware that this would probably break a lot of nixpkgs, but I think it needs to be fixed nonetheless.

@vcunat
Copy link
Member

vcunat commented Dec 25, 2015

There were discussions on this already IIRC (maybe years ago). The "lexical hint" argument actually goes against with completely, and it supports the current semantics. When you use a let-bound symbol, it can't now be magically shadowed by a symbol hidden inside a with-expression.

@edolstra
Copy link
Member

Closing this as there is nothing actionable.

zolodev pushed a commit to zolodev/nix that referenced this issue Jan 1, 2024
Add EditorConfig file and fix errors
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants