simple is not small
37 points by hugoarnal
37 points by hugoarnal
I really enjoy the opinions of serious Clojure people. It feels like we really care about the same things, even though we have opposite views on static types.
Clojure ... care about the same things ... static types
Janet should have static type ability by the end of the year; we have 3 concurrent efforts. Unfortunately, we're not confident enough to assert any unique philosophy yet.
whoa this is big news and seriously re-upped my interest in Janet.
Would you happen to have any links to said efforts? Google is failing my google-fu in finding them.
100% agree on the conflation people often make between simplicity and smallness.
But this point feels off:
The answer to "when should your program be simple?" is: always. There is very little advantage to introducing coupling to parts of your program; it makes it harder for you as a developer to maintain the program, and is less flexible for your users.
Maybe I'm misreading the intent here, but even if we consider the same level of user-facing functionality, complexity can buy lots of things:
To name a few.
I feel these are almost incidental things related to the production deployment of a program rather than its core use. Jyn does concede that "Being small makes sense […when] you're Brian Kernighan and your program is running on a literal PDP-11 […]", though they do not outright acknowledge the tradeoff here.
It would be better to say that these are competing forces. If UNIX is simple-complex and Jyn's CI example is big-simpler then your example of instrumentation would land somewhere around... big-(slightly more complex). Dynamic changes (like feature flags) could be more expensive, which brings us to the delightful prompt of: how do I make my program dynamic while keeping its complexity under control. Simple is not easy, comes to mind.
I comment on the section "Decoupling" from the perspective of my main programming languages being Rust and Lisp(s).
Typed Racket does a similar trick, but using macros so that the type checking happens at compile time instead of runtime.
The author seems to regard Racket's ability to add typing with macros favorably — as would I (although I find Typed Racket, though admirable, neither small nor simple).
If you want to iterate a struct['s fields in Rust] ... get fucked? write a proc-macro?
This, however, seems to be presented unfavorably — but why?
In practice, one would not write a macro to do that but rather use one as a library.
In Racket, one can give a struct static typing through macros — good, right?
In Rust, one can give a struct iterability through macros (even if less sophisticated macros than Racket's). From a Lisp perspective, I don't see that as too bad.
The article does not seem to make any argument for the notion that using macros to allow iterating over a struct's fields is somehow bad, even as it seems to present in a favorable light Lisps' ability to use macros to implement in libraries what otherwise might be language features.
It almost seems to be saying "In Lisps, one gets to use macros to implement what otherwise might be language features, yay! In Rust, one has to use macros to implement what otherwise might be language features, ugh!", with no explanation for this seemingly discrepant attitude towards these two cases.
Furthermore, the article seems to give no consideration to Rust's reasons for making different choices from Clojure and Racket, and seems to ignore the different priorities and intents of the languages' design.
Rust's choices here — including integration (tight coupling) of static typing into the language, and not emitting in the executable file, by default, the information necessary to iterate over a struct — are (among other things) choices in favor of (time- and space-)efficiency by default.
Sufficient effort in compiler optimization (both human effort writing a compiler and compiler effort optimizing a program) might be able to bring all three languages to equal efficiency, but Rust chooses to start from a more efficient baseline. The Lisps surely gain things by focussing less on efficiency than Rust, but it is a trade-off.
I feel as though the article both too quickly dismisses Rust's macros and seems to present the Lisps' choices here as simply better than Rust's without considering the trade-offs involved and the languages' different priorities.
If you want to iterate a struct ... get fucked? write a proc-macro?
That situation could've been so much better if early(ish)-on Rust designers didn't have a fascination with, funnily enough, Lispy hygienic macros (and later with repeating the silliness of Template Haskell)… and instead played with metaprogramming in D.
Hmm, I like the concept of this post but I’ve seen some simple programs become complex with heavy decoupling. Specifically decoupling has a tendency to cause indirection and poor abstractions, both of which can cause a program hard to read and navigate.