Honestly, having watched people argue about what simple is for about the last 10 years, I've pretty much settled on it not being a well-defined term. We know complex when we see it for sure, at least when it is present in quantity, but simplicity is not just the absense of complexity. There's at least three concepts we're all trying to stuff into the same word, and they are not only not "orthogonal" they are often in…
Simple Is Not Small
71–80 of 95 posts
Re: Simple Is Not Small
#72> There's no native Unix equivalent to frequencies, this sort | uniq -c is the closest we can get. Not only is it less performant (it has to collect the full input into memory before continuing), but it ties aggregation to ordering. One of the core features of the Unix command-line is that it is user-extensible. If there's no "native" command equivalent to frequencies, you can write your own, and it will be given the…
Yeah, that point was weak. The argument went from "Unix pipelines are not simple" to "unix based operating systems don't have an equivalent to Clojure's frequency function by default so it's worse" OK but how would it look like if you had such a program? Shells are not known for having the extensive set of functions that real programming languages have.
But Unix pipelines are not simple too. They have a couple of nitty-gritty details that often come out and bite you.
1. They can only stream raw bytes, so all the programs that deal with lists like sort and uniq have to separate items using a delimiter (usually newline). If you want to process data with that delimiter in it, you're in for a ride. And if you want to write a custom tool, you have to do all the splitting yourselves (luckily it's so common most programming language will provide a ready-made facility for you to do that). This is New Jersey approach again: "I'll make my code (the OS, the shell) easier to write, and in return make life harder for my users (the tool writers)".
2. Error are hidden by default in shell. Nowadays you can explicitly change this behavior, but you have to remember to do `set -o pipefail` and I don't think it was always there.
3. There is no data typing at all. Everything is binary or text. Nowadays a lot of programs just output JSON, and the users (if they even stay inside the shell) almost always reach for jq to parse it. But jq is not a Unix philosophy program: it's an entire streaming functional programing that can do quite a lot. But even jq gets hairy when you have to do a bigger query or transformation. In that case users often reach out to Python or another language and just move the business logic there.
I think this fits well with what the article is trying to say: Unix pipes are pretty easy (small) to implement on your own (compare that to something like Nushell's pipes). But the moment you to do something that's a little different than the happy path it was built for, you need to go for another tool (jq) that has its own built-in pipe and small programming language, because Unix pipes won't cut it. And for more complex (hehe) things, you'll have to reach for a larger (and simpler) tool: a full-fledged programming language.
Re: Simple Is Not Small
#73Earlier quoted context omitted.
Yeah, that point was weak. The argument went from "Unix pipelines are not simple" to "unix based operating systems don't have an equivalent to Clojure's frequency function by default so it's worse" OK but how would it look like if you had such a program? Shells are not known for having the extensive set of functions that real programming languages have.
I think the article is a bit weak when it's making this point, because it's not about Unix pipelines. It's about POSIX shell utilities being too bare-bones. But Unix pipelines are not simple too. They have a couple of nitty-gritty details that often come out and bite you. 1. They can only stream raw bytes, so all the programs that deal with lists like sort and uniq have to separate items using a delimiter (usually ne…
I'm not sure if you're actually trying to argue for a specific position here, but you highlight several negative results of one "philosophy" of development, with the implication that the alternative wouldn't have those negatives.
This is a tricky point to refute because you're right, these are flaws and there could be a system that doesn't have them.
So why do these flawed systems exist and proliferate?
Because the real life result isn't actually a choice between "sloppy but quick to develop" and "elegant well engineered but slow".
The choice is actually between "sloppy but exists" and, well, nothing, because the other version never actually materializes.
(And of course, I feel compelled to point out that bash is a user interface not a programming language. Any attempt to replace it or improve it without focusing on that main point is doomed to failure, which is why you see so many people who apparently think that what bash really needs is strict type checking or something and end up creating a completely awful user experience)
Re: Simple Is Not Small
#74Using "length of the correctness statement + length of its proof" works quite well as proxy for complexity of a component (the longer, the more complex). Copy pasted functions with subtle changes mean you cannot reuse the proof (DRY). Giant functions with lots of if/else statements however might cause a branch explosion in the proof. The right abstraction removes lots of assumptions that a proof could depend on, limi…
It sounds like a reasonable concept, but then Principia Mathematica takes 300 pages to prove that 1+1 is 2.
Re: Simple Is Not Small
#75The word simple is used here a way I'm having trouble wrapping my head around. This specific usage appears to come from this linked talk, Simple Made Easy: https://www.youtube.com/watch?v=SxdOUGdseq4 My reaction to the Unix pipeline was that, the reason it exploded in complexity is because the pieces were too simple. They were insufficiently expressive. But the word is used in a different way here, and I'll have to w…
the reason it exploded in complexity is because the complexity is in the interaction of the parts, not the properties of the parts. It's not so much about expressiveness but about the fact that the Unix philosophy has a willful disregard for systems thinking.
Russ Ackhoff has the analogy of the house. How do you design rooms in a house? Only ever with the house in mind. You can't just hope the rooms work, you always need to check whether a new room improves the house, if somethings wrong you fix the room, not the house.
Unix tools have a disregard for the house. Clojure works well because every part of Clojure is designed not just to improve itself but to improve Clojure. Emacs is similar in that regard, you can see that when people make Emacs packages. The good ones always have Emacs in mind, not just their own functionality.
Re: Simple Is Not Small
#76Earlier quoted context omitted.
I appreciate the New Jersey simplicity as a user (with development skills) too, though. It's usually just a matter of time before I have to dive into the program/library/whatever internals to fix a bug.
It's why only nerds use Linux (simple for the developer) but everyone uses Office (simple for the user). Sorry, I meant Microsoft Copilot 365.
From the authors, Charles Simonyi went to Microsoft as one of the original Word implementers, while Excel was born on Mac OS and only later ported to Windows.
Re: Simple Is Not Small
#77> There's no native Unix equivalent to frequencies, this sort | uniq -c is the closest we can get. Not only is it less performant (it has to collect the full input into memory before continuing), but it ties aggregation to ordering. One of the core features of the Unix command-line is that it is user-extensible. If there's no "native" command equivalent to frequencies, you can write your own, and it will be given the…
Re: Simple Is Not Small
#78Earlier quoted context omitted.
It's why only nerds use Linux (simple for the developer) but everyone uses Office (simple for the user). Sorry, I meant Microsoft Copilot 365.
I think Excel is a good example that everyone can build a clear mental model on how to use it, but implementing one is a daunting task.
Excel is great, but it's an arcane beast rivaled only by Emacs configs. People pass down Excel formulas by word of mouth like they're magic spells.
Re: Simple Is Not Small
#79"In Clojure this is fairly straightforward" Somehow when things get complex, I could never find fully functional style to be more understandable than imperative
Maybe part of it is that fully functional notation necessarily preserves certain properties of the computation, while imperative style doesn't have to. For a complex piece of code, all of the hairiness is manifest in a functional style, but can be made implicit in an imperative style. So there's an economy to the imperative approach as things get complex, but in a sense we're just laundering the complexity from under…
Re: Simple Is Not Small
#80I don't see how the example would benefit at all from having that information at run-time when it exists at compile-time. The problem with Rust specifically I think is that it's a relative PITA to get to the information that exists at compile-time in this case. In Zig, you'd just iterate over the fields using the same language you use for run-time code.
const fields = std.meta.fields(@TypeOf(instance));
inline for (fields) |field| {
const name = field.name;
const value = @field(instance, name);
std.debug.print("{s}: {any}", .{name, value};
}
The combination of high dynamicity at compile-time with low-effort switching between compile-time and run-time contexts makes this not too bad.