Neither SML nor Haskell are optimized for expressing deeply nested records with many string literals, for example. The multiline interpolated strings in Nix are extremely much better than in SML or Haskell. The way records and arrays are written is great: SML and Haskell both suffer from the tedious problem of using separators between items instead of after each one; in Nix each item can always be moved without messing with separators.
I think Nix is an engineering marvel up to and including the language design. If you can make a better surface syntax and demonstrate it by translating some significant part of Nixpkgs, I'd be very interested, but I think in general the language is the way it is because that's what made most sense for the system's designers.
Lisp is pretty good at lists.
The only important language is the derivation language sent to the daemon. Nix spends so much time building up inputs... for shell scripts. I always felt like they would have been so much more successful if they chose some other, more popular language to generate derivation.
http://git.savannah.gnu.org/cgit/guix.git/tree/gnu/packages/...
You'll see here that the package emacs-minimal actually inherits from the emacs package definition, and then all fields afterwards are essentially overwrites of whatever was in the emacs package.
Unfortunately, I just noticed that the manual alludes to this, but actually never explicitly documents it in the "Defining Packages" section :/
Purescript's extensible row types handle this process elegantly and if Nix takes a cue from that, it will work great.
let
foo = 42;
bar = "a string";
in {
baz = "deja";
quux = "vu";
}
Javascript: const foo = 42;
const bar = "a string";
return {
baz: "similar",
quux: "but different"
};
You find this kind of thing all over the place. Nix is a much smaller and simpler language syntactically, and more pleasant to write.I don't have extensive ML or Haskell experience, coming from Ruby/Java background.
I think the Nix language works great as a configuration language, and I greatly prefer it to JSON, YAML, or Ruby, which are often used for similar purposes. The way arguments are passed in, merging of attribute sets, the library from Nixpkgs with various list and set operators and other utilities, and great multiline string support make it far superior to those other config languages in my opinion.
My biggest gripe is that the Emacs mode isn't very strong, so I'm often applying indentation manually.
I recently learned about Jsonnet[1] which has some similarity with Nix.
[0]: https://github.com/Gabriel439/Haskell-Dhall-Library [1]: https://github.com/Gabriel439/Haskell-Dhall-Library
Also, the comma-first syntax like
{ foo = "bar"
, baz = "qux"
}
drives me nuts. In the name of all good things in the world, why?
oooh but this is one of those trivial things that I really liked in my brief days of using Haskell, and that has sometimes carried over to my C++, e.g. in initializer lists. I find it super useful because everything lines up nicely, and from the point of view of version control you don't have to edit the previous line to change '}' to ',' when adding a new line.
foo := Foo{
x: 10,
y: 24,
}I wonder if people's aversion to commas first has something to do with the fact that commas have a very familiar use in ordinary writing, and there they always follow a word. It is very common to see BNF grammars written with leading vertical bars, and no one seems to mind that -- in fact it would be unusual to use trailing vertical bars.
By the way, a bunch of languages permit a trailing comma after the last element of a list. This is also nice because it means that if you put each list item on a line, the list items all have the same format (thing plus comma). With the Haskell syntax, you lose this, but there is no reason a language couldn't support a leading comma before the first element of a list.
Not if the language allows trailing commas on the last line, like Python and Go do.
Then you have a comma at the end in ALL lines, including the last one, without an issue. That was what I proposed above (and lots of languages do it, I think JS is adding it too).
- { old-one
+ { new-one
+ , old-one
While trailing commas allow you to insert an element anywhere with just one line addition.This doesn't break anything, but it makes looking at "git blame" so much easier.
None of the above language have all these properties combined.
But... I still love Nix, and you get used to it.
If yes, I can draft a proposal.
So, if only gradual changes are allowed, I would have started with:
- making semicolons optional
- commas for implicit array literals (e.g. "a", "b", "c" in lieu of ["a" "b" "c"]
- something to do with 'with' / 'in' syntax.
In fact, I can live with anything, except non-optional semicolons. Is there a possibility to infer them?
For the array litterals, I don't really see which improvements your syntax brings (except suppressing the space-separated list, which conflicts with the syntax for function application). Is it used somewhere else ?
https://gist.github.com/atemerev/889806081ed8fcb77495666fac9...
For me, it looks infinitely better.
I'm genuinely curious... what makes that a dealbreaker?
I'm someone who has worked in a large variety of languages, including Python (significant whitespace) and Javascript (no significant whitespace).
First: semicolon inference in Javascript is an abomination :). If the language says that whitespace is not significant, then using newlines to infer where semicolons maybe should be... is inconsistent with the statement "whitespace is insignificant".
Second: when I learned Python, I was coming from a primarily Perl and C background. The significant whitespace wasn't a big deal at all because that's how I indent my code anyway. And I would argue (and do in code reviews) that any code that is not indented properly is incorrect because it is extraordinarily misleading to a reader.
So, yeah, for any given programming language, I couldn't care less if whitespace is significant or not, or whether there's semicolons at the end of lines, but god damnit don't go half way on either of those. Indent your code as if whitespace is significant (because it IS to whoever's trying to decipher it later), and stick semicolons at the end of your lines whether or not some stupid inference rule will stick them there for you if you forget.
And as a final rant, "modern Javascript" didn't introduce semicolon inference; it's been there for a long time and was put there to try to lower the barrier for newbies. It wasn't put there because it's a great design decision.
An interesting thing with Scala is that in the BNF, "semi" is defined as ';' or nl.[2] After doing some initial reading about Scala, I was pretty much wondering why Scala needed semicolons at all. What you call "semicolon inference" seems like it's more like "optional semicolons", in that the language doesn't really need them.
[1]https://stackoverflow.com/questions/29743009/in-scala-are-se... [2]https://github.com/jystic/language-scala/blob/master/doc/syn...
If that was possible, and a few $000 was raised (looking at the comments here, I think people would chip in) then a new version of the Nixlang with the same semantics and full backwards compatibility but a cleaner syntax, would be a great project to fundraise for.
(Sexps are usually not my first choice, I think it is a "lazy option" for people who do not want to write parsers / design their own syntax. Even then, they are better than current Nix expressions).
There are some real advantages to having one universal syntax: witness the explosion in XML and, later, JSON (both of which are generally inferior to S-expressions[1]). It'd be pretty great for one person to write one parser, and then everyone forever after to be able to use it. We'd be able to focus on semantics and not on syntax.
[1] Although it is nice that JSON supports first-class associative arrays.
It's a volunteer-run service. It makes sense they don't want to host your proprietary binaries
(I don't see what's wrong with adopting sexps to avoid dealing with custom syntax -- quite the opposite,)
Anyway, thanks for the answer
EDIT: probably the only gripe I would make is to have comma-separated lists instead of having to use parentheses to separate non-atomic expressions.
Wait no separators are evil. This is the best thing about the syntax.
No need to cringe over syntax. Syntax is just syntax. If you are familiar with a better syntax to express Nix in then create a parser from that format to Nix' syntax. Then insert this parser as a pre-processor in the build process, and problem solved.
To me it doesn't feel weird at all: I can't think of any feature that was new or surprising when I started using it and I am not the biggest expert of functional programming. You have to learn more about the standard environment and tools if you want to start contributing to nixpkgs and write your own packages but if you only care about configuring your system nix is as difficult to learn as say, JSON.
It's true that some DSLs are not only different, they're also badly-designed languages or gratuitously different. I guess this is an occupational hazard of DSLs, but it's not unavoidable. It's possible to make the leap to a DSL only when actually beneficial and then to design a DSL that doesn't suck.
Why they wouldn't take the most (syntactically) beautiful functional programming language out there — Standard ML? It would work perfectly for such a task. Or the second contender — Haskell. If C-like syntax is desired, the best contendant is probably Swift.
I cringe every time I have to edit a .nix file (and I have to do it a lot).