A small disclaimer: I’ve lived in India for a few years, I have some good friends there and I think I begin to really understand the some cultural aspects which govern this vastly complex and spontaneous society.

Nowadays everyone, it seems, is either a programmer or an AI researcher or both. When they are not a crapto “engineers”, of course.

Just like chef Gusteau from the Ratatouille movie famously proclaimed – “Anyone can cook”.

Well, bad cooking is easy – one just put the ingredients together and heat it up. Most of the time the result will be tolerated, and will even have some demand if priced cheap enough.

I absolutely love these food porn videos on social media, where they show how Indian non-veg curries were made - they literally put together like 10 different spicy powders (masalaa) in a pod, with meat, gee and curd (why not?!), and then just grossly over-heat it.

There has to be a better way, but it requires a lot of knowledge (and experience) about what is the best match to what, what exact temperature is optimal for this and that ingredient, how long they have to be cooked at that particular temperature and thus what is the proper timing to add stuff in (and how to do it without ruining what has already been done).

Junk-food is the best metaphor I know of about “modern coding” which is being shilled to us as a programming. Almost no one is qualified or even has enough experience, but everyone is advertising their “skills” and cool “projects”.

Literally, just like these makeshift food stalls at a seasonal bazaar. Well, there are always a few masters among them, but this is not the point.

The code we see literally everywhere (nowadays mostly on Github) is a low-effort, never-researched crap by unqualified but very ambitious narcissistic amateurs. It is especially prominent in the Haskell community.

If only one would compare the carefully crafted code of Richard Bird, Graham Hutton, Paul Hudak, Philip Wadler and, of course, SPJ which the crap we see on hackage and Github

The main problem, is, of course, unnecessary, redundant abstractions (which is the root of all evil) and over-abstraction without understanding in general. They just put everything in a pot.

Yes, indeed, just as Peter Norvig, the great (https://www.norvig.com/21-days.html), said: “Bad programming is easy. Idiots can learn it in 21 days , even if they are dummies”. And, boy, they actually do.

Immutability, which is, perhaps, the most profound and universal principle, has been turned by Chuds into that “Nix” abomination, which literally shits on my disks with gigabytes of unnecessary, redundant crap.

The ignorant idiots are trying to enforce it at the lowest, implementation level instead on a proper conceptual level of abstractions.

Well, for that the Chuds have to read (and understand) the classic book by Barbara Liskov (“Abstraction and Specification in Program Development”), which teaches how to define a proper, non-leaking ADT, what are the implications (possibility of having and using multiple implementations), and, most importantly, do not have this problem, which “requires” all this:

ls ~/.stack/snapshots/x86_64-linux/260ea70bfa01bb3c75249eacb12ba7643c201e7a6f18bfe9a2b5327959d557fa/9.6.3/lib/x86_64-linux-ghc-9.6.3/

aeson-2.1.2.1-AtHDhNlMDlXGlQEQo9BMGu aeson-pretty-0.8.10-7bTrb6h5JjV6fkukjlf4nG ansi-terminal-1.0-3kfRbX22CbYKtT7TWkfDm3 ansi-terminal-types-0.11.5-7070YP17lX07wjJ4YjrtXA ansi-wl-pprint-1.0.2-7W2Pb8mhGAZ2C885aRPEnj assoc-1.1-B2oYzvtRAbL6TdG9vtcpvT attoparsec-0.14.4-8EcVDwSMoUiLNbBvSik1jh-attoparsec-internal attoparsec-0.14.4-IisHTJET72jKYnz1Wlbmz9 base-compat-0.13.0-JbgR4gkZn2S7VJJWJHpoE base-compat-batteries-0.13.0-6rnW8gl5KYBFY48L9XeQFH base-orphans-0.9.0-J44kyio6vh9BIquFiEWgdc bifunctors-5.6.1-BKBejTD5rTW2Cwk3hpbNKZ cmdargs-0.10.22-Bo66f0Kl3eE5G8AycK8y3n colour-2.3.6-CL1PpcKDPAc8DjPzbsln3V comonad-5.0.8-7VmOZq2W2aPEc92Us4CIJR contravariant-1.5.5-D7uv6gRHfsshi2SiSflrv data-default-0.7.1.1-3YvGn2u185f1XWhdramjaH data-default-class-0.1.2.0-5FK3vpOLcdkKGIel7pORbQ data-default-instances-containers-0.0.1-4iMZsUnb16EAGSBDaolDhW data-default-instances-dlist-0.0.1-IZH6bFs7BObEUaakPOxb0v data-default-instances-old-locale-0.0.1-2s6n6c5MnQ7LChnI5uCwHf data-fix-0.3.2-LxyWgDBHbHh457Ex3XUnTI distributive-0.6.2.1-91VzmrRDrQ29F0tHcRSIMo dlist-1.0-EiNZyHbYIYq9Gl8u0nmg6M free-5.2-6t18XEmCbtvCVgcZ5FDJ32 generically-0.1.1-EkcRYhUnPJ57wDcdcrdfk6 hashable-1.4.3.0-Cy9XuTuozCgAdsdKEf3KNi haskell-src-exts-1.23.1-6bq8L1rOeseFIOXsg52Nca indexed-traversable-0.1.2.1-HT9WlttgftJ3Yjcmj6Vls1 indexed-traversable-instances-0.1.1.2-3HUB7EIjq533qow89Uyy4h integer-logarithms-1.0.3.1-6BMdz0fAUjKELClrM8UIuk libHSaeson-2.1.2.1-AtHDhNlMDlXGlQEQo9BMGu-ghc9.6.3.so libHSaeson-pretty-0.8.10-7bTrb6h5JjV6fkukjlf4nG-ghc9.6.3.so libHSansi-terminal-1.0-3kfRbX22CbYKtT7TWkfDm3-ghc9.6.3.so libHSansi-terminal-types-0.11.5-7070YP17lX07wjJ4YjrtXA-ghc9.6.3.so libHSansi-wl-pprint-1.0.2-7W2Pb8mhGAZ2C885aRPEnj-ghc9.6.3.so libHSassoc-1.1-B2oYzvtRAbL6TdG9vtcpvT-ghc9.6.3.so libHSattoparsec-0.14.4-8EcVDwSMoUiLNbBvSik1jh-attoparsec-internal-ghc9.6.3.so libHSattoparsec-0.14.4-IisHTJET72jKYnz1Wlbmz9-ghc9.6.3.so libHSbase-compat-0.13.0-JbgR4gkZn2S7VJJWJHpoE-ghc9.6.3.so libHSbase-compat-batteries-0.13.0-6rnW8gl5KYBFY48L9XeQFH-ghc9.6.3.so libHSbase-orphans-0.9.0-J44kyio6vh9BIquFiEWgdc-ghc9.6.3.so libHSbifunctors-5.6.1-BKBejTD5rTW2Cwk3hpbNKZ-ghc9.6.3.so libHScmdargs-0.10.22-Bo66f0Kl3eE5G8AycK8y3n-ghc9.6.3.so libHScolour-2.3.6-CL1PpcKDPAc8DjPzbsln3V-ghc9.6.3.so libHScomonad-5.0.8-7VmOZq2W2aPEc92Us4CIJR-ghc9.6.3.so libHScontravariant-1.5.5-D7uv6gRHfsshi2SiSflrv-ghc9.6.3.so libHSdata-default-0.7.1.1-3YvGn2u185f1XWhdramjaH-ghc9.6.3.so libHSdata-default-class-0.1.2.0-5FK3vpOLcdkKGIel7pORbQ-ghc9.6.3.so libHSdata-default-instances-containers-0.0.1-4iMZsUnb16EAGSBDaolDhW-ghc9.6.3.so libHSdata-default-instances-dlist-0.0.1-IZH6bFs7BObEUaakPOxb0v-ghc9.6.3.so libHSdata-default-instances-old-locale-0.0.1-2s6n6c5MnQ7LChnI5uCwHf-ghc9.6.3.so libHSdata-fix-0.3.2-LxyWgDBHbHh457Ex3XUnTI-ghc9.6.3.so libHSdistributive-0.6.2.1-91VzmrRDrQ29F0tHcRSIMo-ghc9.6.3.so libHSdlist-1.0-EiNZyHbYIYq9Gl8u0nmg6M-ghc9.6.3.so libHSfree-5.2-6t18XEmCbtvCVgcZ5FDJ32-ghc9.6.3.so libHSgenerically-0.1.1-EkcRYhUnPJ57wDcdcrdfk6-ghc9.6.3.so libHShashable-1.4.3.0-Cy9XuTuozCgAdsdKEf3KNi-ghc9.6.3.so libHShaskell-src-exts-1.23.1-6bq8L1rOeseFIOXsg52Nca-ghc9.6.3.so libHSindexed-traversable-0.1.2.1-HT9WlttgftJ3Yjcmj6Vls1-ghc9.6.3.so libHSindexed-traversable-instances-0.1.1.2-3HUB7EIjq533qow89Uyy4h-ghc9.6.3.so libHSinteger-logarithms-1.0.3.1-6BMdz0fAUjKELClrM8UIuk-ghc9.6.3.so libHSmonad-dijkstra-0.1.1.3-CgVzvieVxhx2JPRSo7EHqY-ghc9.6.3.so libHSold-locale-1.0.0.7-OpLxQwSdbqHzI1qJrI5NI-ghc9.6.3.so libHSOneTuple-0.4.1.1-3xROWIPE1CT4QZlQuFvzgR-ghc9.6.3.so libHSoptparse-applicative-0.18.1.0-5cbl2zXi6SE2pC3wd7rg7U-ghc9.6.3.so libHSprettyprinter-1.7.1-5e7OiMaiyLWFEOfH8r8oT4-ghc9.6.3.so libHSprettyprinter-ansi-terminal-1.1.3-4Ig0UpU6YgF9y9AFEicGiL-ghc9.6.3.so libHSprettyprinter-compat-ansi-wl-pprint-1.0.2-GfW9Eya3Gwc5xywUHVIlks-ghc9.6.3.so libHSprimitive-0.8.0.0-Jo5jlESTXJeEofOqAuqg9C-ghc9.6.3.so libHSprofunctors-5.6.2-4f0ilW1gMatAhGo5L3LEyL-ghc9.6.3.so libHSpsqueues-0.2.7.3-2kvLBLtRyjxI4EXBl9dKvi-ghc9.6.3.so libHSQuickCheck-2.14.3-3pqw5pyBKGqHO3NbSB9C7y-ghc9.6.3.so libHSrandom-1.2.1.1-I7RCALOFfYGFaJvIapv0Ql-ghc9.6.3.so libHSscientific-0.3.7.0-KNaRCO8KEOFA8E2t5UN5Bi-ghc9.6.3.so libHSsemialign-1.3-2GwwSRQ97db1tic40Nc1OT-ghc9.6.3.so libHSsemigroupoids-6.0.0.1-BO0d9UKfiwM2rKjtaDXfIv-ghc9.6.3.so libHSsplitmix-0.1.0.4-3LPiSuZCzhU6PeA3JszOX5-ghc9.6.3.so libHSStateVar-1.2.2-LE1zE95ecHb3rKz2GzNMvC-ghc9.6.3.so libHSstrict-0.5-4zd7ONntlnWFbP40qKstE9-ghc9.6.3.so libHStagged-0.8.7-DqRkQTFiCFVIkc5ul6U7ms-ghc9.6.3.so libHStext-short-0.1.5-2mzATDPgHcEDIpJmXzh33-ghc9.6.3.so libHSth-abstraction-0.5.0.0-JD9vmJ369jBCu5VUUIjZuj-ghc9.6.3.so libHSthese-1.2-IKneMuHnSS84xFpHBzbRdQ-ghc9.6.3.so libHStime-compat-1.9.6.1-DlgiqBexBaS23LqsxahfKQ-ghc9.6.3.so libHStransformers-base-0.4.6-1AaMvJ2gX4DSSZfr5Ad54-ghc9.6.3.so libHStransformers-compat-0.7.2-9x8A6zWhyVKLofAGiBIUux-ghc9.6.3.so libHSunordered-containers-0.2.19.1-BWYtaJ8jCLn9nFdaUg5lKu-ghc9.6.3.so libHSuuid-types-1.0.5-BoZZBLnt7jULlvbkdidkgS-ghc9.6.3.so libHSvector-0.13.0.0-DQjDtT0hTdSECzYvtVe6dV-ghc9.6.3.so libHSvector-stream-0.1.0.0-46tIj2XpJ1K5aHx2g36wqS-ghc9.6.3.so libHSwitherable-0.4.2-5Hu3Nk4QTme835unXarsGj-ghc9.6.3.so monad-dijkstra-0.1.1.3-CgVzvieVxhx2JPRSo7EHqY old-locale-1.0.0.7-OpLxQwSdbqHzI1qJrI5NI OneTuple-0.4.1.1-3xROWIPE1CT4QZlQuFvzgR optparse-applicative-0.18.1.0-5cbl2zXi6SE2pC3wd7rg7U prettyprinter-1.7.1-5e7OiMaiyLWFEOfH8r8oT4 prettyprinter-ansi-terminal-1.1.3-4Ig0UpU6YgF9y9AFEicGiL prettyprinter-compat-ansi-wl-pprint-1.0.2-GfW9Eya3Gwc5xywUHVIlks primitive-0.8.0.0-Jo5jlESTXJeEofOqAuqg9C profunctors-5.6.2-4f0ilW1gMatAhGo5L3LEyL psqueues-0.2.7.3-2kvLBLtRyjxI4EXBl9dKvi QuickCheck-2.14.3-3pqw5pyBKGqHO3NbSB9C7y random-1.2.1.1-I7RCALOFfYGFaJvIapv0Ql scientific-0.3.7.0-KNaRCO8KEOFA8E2t5UN5Bi semialign-1.3-2GwwSRQ97db1tic40Nc1OT semigroupoids-6.0.0.1-BO0d9UKfiwM2rKjtaDXfIv splitmix-0.1.0.4-3LPiSuZCzhU6PeA3JszOX5 StateVar-1.2.2-LE1zE95ecHb3rKz2GzNMvC strict-0.5-4zd7ONntlnWFbP40qKstE9 tagged-0.8.7-DqRkQTFiCFVIkc5ul6U7ms text-short-0.1.5-2mzATDPgHcEDIpJmXzh33 th-abstraction-0.5.0.0-JD9vmJ369jBCu5VUUIjZuj these-1.2-IKneMuHnSS84xFpHBzbRdQ time-compat-1.9.6.1-DlgiqBexBaS23LqsxahfKQ transformers-base-0.4.6-1AaMvJ2gX4DSSZfr5Ad54 transformers-compat-0.7.2-9x8A6zWhyVKLofAGiBIUux unordered-containers-0.2.19.1-BWYtaJ8jCLn9nFdaUg5lKu uuid-types-1.0.5-BoZZBLnt7jULlvbkdidkgS vector-0.13.0.0-DQjDtT0hTdSECzYvtVe6dV vector-stream-0.1.0.0-46tIj2XpJ1K5aHx2g36wqS witherable-0.4.2-5Hu3Nk4QTme835unXarsGj

One more time: abstraction by specification has to be done at the lavel of stable interfaces, such that implementations are not even a concern.

Just like it has been done with good quality, properly desinged and well-crafted stdlibs (of SML, Haskell, Ocaml Scala and Go), I do not care about the actual implementations of the List module as long as the specifications holds. Same is true for all the other major ADTs.

Nothing of that fucking abomination displayed above is required or necessary.

Specifications and immutability at the interface level (and of the bindings) is at the core of proper programming (and mathematics).

This has lots of implications. One would have discover that the TLA+ system is about checking and proving the properties and invariants at an interface level.

That the defuns and defstrcuts are enough to implement the CLOS, or that the core OCaml is enough to define an Object System (an extension, which is a set of embedded DSLs) and other remarkable, principle-guided achievements.

All this was possible because of stable (immutable) interfaces. When we must change something we must define a new (versioned, perhaps) interface, /just exactly as if we have to define a new binding with a new symbol (as in Erlang).

We could also define a new binding which will shadow the previous one in a particular scope. The module system of modern Ocaml has been done just right and has all these well-researched mechanisms implemented, including that “open” keyword.

Last but not least, even that narcissistic Rich Hickey in one of his talks (I do not remember which, because they all so poorly structured) got it right with the reference to the Maven repository as an immutable structure and that this very property is the key to its usability at a global scale.

One cannot change any of already published packages (and the interfaces they export), only to “extend” the repo with a new version on a corresponding branch.

This is exactly the fundamental (and even universal) principles at work. Another instance is the whole Haskell type hierarchy (composed of individual modules which extend it with new “branches”).

The modularity principle is what holds the Chud-infested low-effort Haskell ecosystem together (keeps it from collapsing). Again, modularity is as fundamental as partitioned environment or individual cells.

And this, finally, after taking a whole “round trip”, brings us back to the “extensions methods” of Scala (stolen from it without understanding, like everything else, by Kotlin).

The concept, not surprisingly, is very similar to Haskell’s type-classes which are named sets of required (to be implemented according to informally stated “laws”) interfaces.

We just concatenate a new set of interfaces, without nesting or sub-setting of the concepts, and thus “extend” a type with a new Trait.

Let the mix of terminology from the different meme-languages not to confuse you – they all just different names for the same poorly generalized universal notions, which are:

  • Immutability at the level of “stable” interfaces.
  • Ensuring specifications instead or implementations.

This principle holds all the biology together and is the basis of Life Itself. No fucking hashes required.

But Who Am I to tell to the Chuds how to do things.