Live data from Hacker News

Simple Is Not Small

jyn.dev

51–60 of 95 posts

Re: Simple Is Not Small

#51
It's a nice dissection of the topic. But I would like to reframe it as "Simple Is Not 'Always' Small."

Logic that the blog presents is sound; but sometimes small works as a good-enough proxy to get to the simplicity that we find elegant.

Re: Simple Is Not Small

#52
post #20

> 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…

I imagine just ask would be enough for most usecases:

awk '{ freq[$0] += 1 } END { for (n in freq ){ print freq[n] " " n } }' < file.txt

Re: Simple Is Not Small

#53
post #47
post #20

> 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.

I think the point was more that it's hard to compose shell utilities to make something new that's not supported out of the box. Instead you do have to write an entirely new utility and use that.

That said having key/value semantics and not just stream of bytes would make the shell much more versatile, at the cost of making it bigger.

Re: Simple Is Not Small

#54

Strong resonance with the famous essay "The Rise of Worse is Better" [1], which contrasted the (better) "MIT/Stanford style of design" with the (worse) "New Jersey approach". MIT/Stanford: > Simplicity -- the design must be simple, both in implementation and interface. It is more important for the interface to be simple than the implementation. New Jersey: > Simplicity -- the design must be simple, both in implementa…

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.

Re: Simple Is Not Small

#55
This is beside the point, and I'm being pedantic, but the unix pipeline and the clojure expression don't quite do the same thing.

The clojure expression reads the entire file into memory first, and then operates on that memory representation.

The pipeline processes the input in chunks. The two `sort`s might read the entire contents into memory, but an implementation like GNU sort will instead, for large inputs, create temporary files for sections of the input and then merge sort them to the output.

You could make clojure do the same thing, but it might not be as "simple" as the pipeline.

Re: Simple Is Not Small

#56

> Unix pipelines are not simple But they are. UNIX Pipes do not mandate having to use tons of different programs with stupid commandline options. I simulate them in ruby itself; method chaining works in a very similar way, but I built a pseudo pipe around it. The idea was more to have an object oriented shell, e. g. combine good ideas from UNIX pipes and the MS powershell. They are simple if you design them well and…

> But they are.

Did you remember to:

- check for the other spawned process exit code?

- waitpid for all process in the other process chain?

- propagate/handle signals, like for example SIGINT/SIGTSTP/SIGPIPE/SIGHUP forward and back signals?

- change stdio buffering mode?

- remember to count how many bytes actually were written by write, and blocking if not, before clobbing the 64kb of the pipe buffer size with another write?

- flush, then close all file descriptors left behind by the pipes when it ends?

It's for reasons like that, that I don't trust anything non-trivial, not-shell to use pipelines correctly.

Re: Simple Is Not Small

#57
post #24

"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 understanding the machinations of the code to understanding the correctness of the code.

Re: Simple Is Not Small

#58
post #40

Another solution to the pipeline example, this time making use of a subprogram for the frequency/accumulation: If you don't allow `awk` in your "pure bash" then ofc this is not satisfactory. But it has the upside that the associative arrays are pretty explicit data structures (for the ordering and counts, respectively).

Nice to see more people getting nerdsniped by the sh code. ;-) Yes, associative arrays work well. I think it should even be possible to use bash associative arrays. But at that point you're no longer doing classic sh - awk is basically halfway to Perl. (And pretty awesome.)

Yeah, insisting on "only" shell is weird, shell is at heart a process orchestrater, and denying it it's processes is rejecting most of it's functionality. It is equivalent to saying "do this in python, but you are not allowed to use any modules"

Without processes shell is just a weird sad little language, with them it turns into this epic data flow language. With some real design stinkers, Most of these are due to it's interactive first focus, The features desirable for interactive use, often start to stink for stored program use, I will note that having the same language for interactive and scripting is pretty kick ass.

On the subject of dataflow languages has there been any research in this area? Something that can stitch together processes as well or better than shell? Perl may work in this role but I have to admit I really dislike it's syntax, and as such I never learned Perl enough to love it. and while most other scripting languages can technicaly create pipelines, it is very awkward compared to shell.

Re: Simple Is Not Small

#59
post #53
post #47

Earlier 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 point was more that it's hard to compose shell utilities to make something new that's not supported out of the box. Instead you do have to write an entirely new utility and use that. That said having key/value semantics and not just stream of bytes would make the shell much more versatile, at the cost of making it bigger.

That's not what the linked article is saying. The point made in the article is that the 'uniq' utility couples together two unrelated concepts--sorting and frequency counting--and this coupling forces you to write more complex code, compared to the version where frequency counting is decoupled from sorting.

All of this is completely correct, but it has nothing to do with bash vs. Clojure. The same decoupling can easily be achieved in either language.

Re: Simple Is Not Small

#60
post #54

Strong resonance with the famous essay "The Rise of Worse is Better" [1], which contrasted the (better) "MIT/Stanford style of design" with the (worse) "New Jersey approach". MIT/Stanford: > Simplicity -- the design must be simple, both in implementation and interface. It is more important for the interface to be simple than the implementation. New Jersey: > Simplicity -- the design must be simple, both in implementa…

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.

Post reply on HN