I think the Nix language has a bunch of unintuitive sharp corner cases.
I tried to make a short expression that contains a few of them, to confuse.
{ a ? f ? a, f, g }:
with { x = "a"; g = _: g; };
!f a ? x && g x a
I think the Nix language has a bunch of unintuitive sharp corner cases.
I tried to make a short expression that contains a few of them, to confuse.
{ a ? f ? a, f, g }:
with { x = "a"; g = _: g; };
!f a ? x && g x a
The intended counterintuitive things are:
?
refers to defaulting the argument, the second ?
refers to checking if f
has an a
entrya
does not refer to the first a
f
, which is a function, can be used as the left-hand side of ?
without errorf
is a functor which can be called and used as an attrset!
applies to f a ? x
and not f
, f a
, or f a ? x && g x a
x
in the right-hand side of the last ?
does not refer to the x
from the with
, but the x
in g x
doesg
after the &&
does not refer to the g
from the with
Same as I think with most languages; you’re not really going to see these edge cases in “real” code, so they aren’t particularly impactful in day-to-day use. You can write unreadable gobeldygook in all languages, see codegolfing. The lack of variable names and clear purpose only obfuscates it more.
I think the difficulty of finding the origin of error messages, especially in conjunction with NixOS, is far more of an issue.
with
and ?
are definitely known to be a bit confusing, though. with
especially is considered an antipattern, you’ve not even shown the worst. Explicitly named variables having priority is pretty easy to grok once you’ve come across it, but what happens if you have two with
s that share an attribute name?
I didn’t want to say Nix is more unintuitive! It’s just a bit of fun to bring out all the sharp corners of the language.
I decided to make another one
value:
with {
value = null;
other-1 = null;
other-2 = value;
}; {
${other-1} = value;
${other-2} = value;
${value} = [ other-1 other-2 ];
}
This one is a function that throws if the argument is anything other than null
and returns an empty attribute set otherwise.