nix & nixos are by far the worst way to manage system configuration, except for any other way that's been tried. imagine if there was something with declarative system configuration _not_ written in an insane undebuggable recursive nightmare of a language/stdlib? oh well, I'll keep using it, because what other options are there?
+1, Guix is quite good with some tricks up it's sleeve compared to Nix.
I am not a fan of S-expressions but using scheme is more reasonable than nix+bash to me.
On the negative side, guix can be slow. It is also not a very pragmatic os. NixOS does non-free firmware and drivers without issue. You need to jump through some hoops for this with Guix. This is not an issue if you plan to run guix in a VM though.
I mean it's pretty wild to take s-expressions and not call them extremely terrible to read. The nix language sucks really badly, but I gladly take it over writing S-expressions.
It reads almost the exact same as any functional C-style language. Not to mention that specifically for Guix, you're going to be writing the (name value) form for 99% of it.
> you're going to be writing the (name value) form for 99% of it.
That's exactly the part that is wrong with Guix, and Scheme in general. Scheme has associated lists, they are written as '((name . value) ...), but since that's too ugly everybody makes macro wrappers around them to get them down to just (name value). But that means you aren't dealing with an obvious data type anymore, but with whatever the macro produces and if you want to manipulate that you need special tools yet again. And then you have record-type and named arguments which are different things yet again, but all serve the same name->value function as an associated list. Names themselves are sometimes symbols, sometimes keywords, and sometimes actual values. Same with lambda, sometimes you need to supply a function, other times there is a macro that allows you to supply a block of code.
It's like the opposite of the Zen of Python, there are always three different ways to do a thing and none of them as any real advantage over the other, they are just different for no good reason and intermixed in the same code base.
I have never seen anything else use the (name value) syntax. You do deal with obvious data types, the REPL tells you exactly what those data types are (records, in the case of Guix). Schemes outside of Guile don't even have keywords, much less named arguments.
Are you complaining that a language has both associative containers and structs? Which one do you advocate for removing in Python to keep up the precious "Zen"?
Lisp programmers have used editors that count the parens for them for decades. Many use something like paredit that simply automatically adds the final paren. I've written significant amounts of Lisp and you simply don't see the parens. You might as well complain about French having all those accents. It's just a different language. Learn it and you'll see why.
I can write lisp. That a lot of lisp programmers require special editors to handle it should tell you enough. It's not that the language is unworkable. You can definitely write stuff in it. The point is that it is quite far from something that should be written by people, in my opinion.
Are you really going to argue that a good programming language is one where you can construct it character by character, by hand? Emacs has existed for decades and it runs basically anywhere. Nobody is programming in ed (well, apart from Dave Beazley[0]). With LLMs the world is finally catching up to the fact that programming isn't typing characters one by one. Lisp programmers have been at this for decades.
I consider it essential for a programming language for people that it is easy to understand things by looking at things locally. Requiring/strongly encouraging extremely deep nesting is not conducive to that.
This is not some weird opinion I have. There is a reason "flat is better than nested" is part of the pretty popular zen of Python.
Most code is read much more than it is written, at least I read much more code than I write. So for me code should be optimized to be read as plain text as that is basically what every tool uses. Requiring a separate tool to get basic readability is not really acceptable. I can't do that on github, I can't do that with the various diff tools, I can't just quickly cat a file or use the countless other tools that are designed to present plain text.
If I then can choose between guix and a language that doesn't require these hoops and extreme quality trade off the choice is not hard.
Anyway if you think guix is better than nix, than nothing stops you from using it.
I just have a hard time taking such a comment seriously, because I have made it myself. Many times even. My second comment on Slashdot in 1999 was a comment just like yours. I try to tell myself it is ok because I was still a teenager.
7 years later I had to write common lisp and I think the parens were a problem for about a week. Since then I have written many thousand lines of lisp code. I usually go back and forth on what I like the most. ML (ocaml mostly) or (guile) scheme. In just about every other language (except maybe factor) I miss the macros (even syntax rules ones) way more than I like the extra expressiveness of, say, Haskell. [0]
Wisp is a part of guile. So you can write your own config using it. It is not completely straightforward, but if you really hate parentheses it is a way. Or you continue the wonderful string gluing of Nix. Whatever floats your boat.
[0]: I do miss typing sometimes in scheme though. I have thought about vibe coding a prototype of an s-expr language that compiles to f# AST.
This isn’t about whether someone can get used to parentheses. Obviously they can. I don’t doubt your extensive experience there. The question is what the language optimizes for by default.
My argument is that S-expressions optimize for structural uniformity and macro power, but they do so at the expense of plain-text readability without tooling. And that trade-off matters in contexts where code is frequently read outside of a fully configured editor, code reviews, diffs, quick inspection, etc.
Saying “editors solve this” doesn’t really address that, it just shifts the burden to tooling. In contrast, many other languages aim to be reasonably legible even in minimal environments.
So I’m not arguing that Lisp is unusable. I’m saying it makes a different set of trade-offs, and for my use case where I spend much more time reading other peoples code in some web portal and with basic terminal tools those trade-offs are a net negative. I would expect this trade off holds for most code produced.
All syntaxes look like windy grass to someone who is not used to them. I think that, while the parsing overhead for lisps might be higher, there is nothing else going on with precedence or syntax. Reading ocaml or haskel operator soup is in my opinion way more taxing than reading verbose scheme code - if it is well formatted.
> This is not a language that is optimizing for being written by humans
I've taken a look at the code - having never written a line of Guix in my life - and it seems very readable to me. It's cleanly structured and makes good use of indentation.
The string "))))))))))", which you claim you're seeing 'regularly', appears exactly twice in 4,580 lines of code. It's the longest parens string that appears in the file. Seems to me like you deliberately searched for the most atypical example, that you're now misrepresenting as 'regular', when it is highly atypical.
And honestly, what would that look like in some 'more normal' language?
);
}
);
];
};
)()();
Better?
I will never understand this fear response some people have to seeing `(fn a b)` instead of `fn(a, b)`.
I indeed searched for the longest chain. Something that happens in 4.5k lines twice is hardly rare. And even if you take away a brace it occurs even more frequently.
And yes your example is better, but still terrible. The point is not the formatting. The point is that there is that 10 deep nested code is just not easy to understand. I would also say a line of c/python that does 10 nested function calls as unreadable. But they do not encourage this, whereas with lisp its modus operandi to write such incantation.
> Something that happens in 4.5k lines twice is hardly rare.
Provided you don't consider the context, sure. One of them is software with buggy tests, the other is one that provides a custom test suite that basically has to be reimplemented in the package definition. How often do you think either of those things happen?
Looking at a lot of nix package expression: Quite a bit. Besides, just taking a way a single brace gives 7 hits. Still a ridiculous level of nesting. So I don't go with your reasoning that these are some kind of super special cases. If something happens so often in 4500 lines of code you cease the right to claim it is special.
It happens 1/2290 (0.04%) of the time. You are significantly more likely to guess a stranger's birthday totally at random (0.27%) twice in a row (0.07%). If you don't consider that exceedingly rare, then you and I need to hit up Vegas immediately.
You are projecting a programming style onto Lisps that's quite alien to them. Lisps tend towards small, discrete functions that are composed together. It is the ordinary languages that tend towards deep branching and nesting; Lisps generally favour recursion and function composition instead.
There are 101 `(package` definitions and 58 out of them have more than 6 nest level, which I would consider more than excessive. That's an incidence of over 50%.
Beside I don't think I'm alien to the functional way of writing things. I write mostly Haskell professionally. But Haskell doesn't casually suffer from making insane expression nesting the default.
You may not be a stranger to the functional style, but you do seem a stranger to the Lisp style, which is closely allied. A lot of FP originated in Schemes and Lisps - Haskell is greatly influenced by the ML family, which is itself greatly influenced by Lisp. Modern FP is a style that would be recognisable to a Lisp programmer fifty years ago, when everyone else was writing imperative soup.
I don't think there's much anyone can say that's going to change your mind. You're strongly coming off as though you've formed a view, based on little experience, and will now Ctrl-F cherry-picked examples to sustain it rather than listen to any contrary information. I respectfully suggest greater open-mindedness and a willingness to reserve conclusions in the absence of data.
I personally don't use Lisp too much, so I'm not particularly invested in this exchange, but I know from experience it's not even remotely what you're describing it as. Everything about Lisps tends towards minimal nesting, from the use of paredit to edit expressions through REPL-based workflows.
The only thing this exchange has done, as someone who programs in FP exclusively, is make me reminisce about and yearn for Lisp. It's a wonderful language for FP.
That link isn't working for me (something about AI detection), but as a point of accuracy, those aren't derivations, they're simple source files. Derivations are generated out of them.
As for the closing braces, would it be better if you had a newline between each?
if an attacker is in the position to try to MITM TLS, they're in the position to just serve whatever they want on port 80 even if your server isn't doing that.
that is _purely_ netflix's decision; they have decided not to integrate. in fact, earlier this year netflix accidentally rolled out their internal version which has full integration with the APIs and then said "oopsie" and removed it again.
Yep. The APIs have always been publicly available for streaming services to use, Netflix just refuses to use them.
The reason is pretty obvious. Netflix would rather have users open their app directly so there’s opportunity to shove things in their faces, collect data from their browsing, and ideally become positioned as the user’s “main” streaming app. The user having a hub app and treating Netflix as one of several services directly opposes their aims.
The situation shares a lot of similarities with Spotify, which also refuses to take advantage of native APIs for the same reasons. Though in their case, there’s an added layer of irony with how they make all a big ruckus about how Apple needs to open their platforms up only for them to pretend APIs don’t exist after Apple adds them. As an example Apple had to hardcode a hack into HomePods to enable Spotify to work with them; where most services (Pandora, Tidal, etc) hook the official HomePod streaming APIs which pull directly from the service to the device, for Spotify Apple has to automatically AirPlay Spotify playing on the user’s phone to the HomePod. It’s ridiculous.
Good news for you, their local hub is available and I currently have fridge and freezer (and a few other sensors) hooked up to home assistant via it right now.
No they won't. I've seen them coming a looooong way. I even re-baptised arduidiots [0] quite a while ago. Since the "branding" fiasco I've stayed well clear of them.
that's not mostly what car enthusiasts care about, especially somebody buying a 150k porsche; they care about handling and road feel and a fat pig of an EV will never match a lighter car (well set up) on that; you can't beat physics when you're slinging that much weight; even set up as well as can be, a 5000lb taycan doesn't come close to the handling feel of a 3250lb 911.
A BMW i3 weighs about 3000 lbs. They’re mostly fiberglass and have a small battery. The center of gravity is probably comparable to the 911 even though it’s tall and goofy looking (all the weight is in the battery, under the seats).
The tire geometry causes a bit of oversteering, but they generally corner well, etc.
Signal is an app whose distribution is controlled by the same people that say they don't have access to your data.
They could at any point push an update that decrypts your messages locally and pushes them decrypted to a server. The only way to prevent this would be to verify each binary update to signal matches the source code, and no modifications have been made to the source to do this.
yup, I ended up implementing that myself via a coredns extension that does DNS for both tags and hosts. obviously not zero effort, but it ended up being quite straightforward, and has been working flawlessly since then.
reply