Comment by dzonga
3 days ago
beautiful work. clojure is very nice. one of the most impactful talks I have ever seen was from Rich Hickey - simple made easy.
however my only gripe with clojure while it's easy to write and comprehend at first - it's difficult to read. & yet most our time we read code not write it. but then again it might be my lack of brain power.
I agree with you, but perhaps in my own way. Jumping into an arbitrary Clojure program can be tough, since the data shapes may not be defined anywhere. Hopefully the program uses spec or malli, but even then, unless they annotate every function with the shape it expects, you may be left needing to REPL in and poke around. However, REPLing in to check just a function or two may not be easy if the program requires some setup and doesn't use integrant or similar.
Once Clojure parity is achieved, I'm interested in static typing, pattern matching, value-based errors, and some other opt-in improvements that I think will greatly improve both readability and toolability (i.e. how well tooling can work with the code, based on what it knows of the code). Stay tuned. :)
What’s your take on Hickey’s talk titled “Maybe Not” which fundamentally criticizes static types? Is there a middle ground where some form of static typing makes sense in a Clojure-esque world?
https://youtu.be/YR5WdGrpoug?si=4mI8doBX6jj6PJkk
Rich has many great ideas and he founded Clojure. I respect him deeply. On typing, however, we do not agree entirely.
For a practical example of a Clojure-like language with a completely static type system (with affine typing), see Carp. https://github.com/carp-lang/Carp
I don't see why there can't be a Carp mode in jank, with bridges in place to connect the Clojurey world from the Carpy world. This would allow jank users to develop interactively to start with, figure out their shapes, use the REPL, etc. Then, if they want, they can lock down some parts of the code for both performance and correctness gains.
1 reply →
Heh. Hickey once debated with me at length about visual neuroscience, a subject I have a master's degree in and he doesn't. At no point did this stop him from confidently asserting things.
I have to wonder if "Maybe Not" is similar, since he's not actually an expert in types, either afaik.
Alexis King wrote a partial rebuttal to Maybe Not: https://lexi-lambda.github.io/blog/2020/01/19/no-dynamic-typ...
8 replies →
Been a while since I've watched/read it, but I remember the ideas in Maybe Not being quite interesting.
To me, the really important idea wasn't a criticism of static types in general.
Instead it was the idea that static typing in most (all?) mainstream implementations conflates concepts that should be separate, specifically the shape of the information that we have (e.g. what fields of what types), and whether a particular bit of information is available and required (e.g. nullability).
He contends that the former belongs in our usual "type definition", whereas the latter relates instead to a given context. For example, my PassportForm type always has a date-of-birth field in its _shape_, but whether it's statically required/present to exist depends on whether we're at a HTTP API boundary, an internal domain function boundary, writing into a database.
It sounded like that kind of "nullability masking" was intended as a feature of Spec, but I don't get the impression it was ever implemented.
I don’t think Rich was criticizing static types as much as saying that they aren’t giving you as much benefit as you think they are and that they complicate program evolution over time.
4 replies →
If you need confidence in the operation of a function you make code testable. If you need it to execute in Repl you need to make code Replable and I am not joking.
If you can run it, then you can REPL it, no matter how deeply nested. Scope-capture (https://github.com/vvvvalvalval/scope-capture) has been probably the most important tool in my box. Hope jank supports it eventually.
Thanks for jank! It’s great to be reading about it, listening to you talking about it at conferences, and I can’t wait to try it out!
> pattern matching, value-based errors
I did not know these were in the cards, that makes jank even more exciting!
Core spec is enough. Types do not tell the truth. Contracts do the data type casting and data testing. A ubiquitous combo in data engineering.
My comment to code ratio is magnitudes higher in Clojure than in other languages, which helps a lot with this.
Also writing Clojure can be incredibly terse, resulting in quite high-effort when reading. Conversely, a lot of time I can condense hundreds of lines of equivalent python into 5 or 6 lines of Clojure. Having all of this functionality condensed into something you can fit in a tweet really helps for grokking larger parts of the dataflow or even larger system. So there are tradeoffs
Plus structural editing and the repl really help with the “reading” experience (reading in quotes because it’s much more interactive than reading)
> Conversely, a lot of time I can condense hundreds of lines of equivalent python into 5 or 6 lines of Clojure.
I'm curious if you have any example of this? Even if it's an hyperbole, I don't really see how.
In my (limited) experience with Clojure and other functional languages, this is usually true under situations where:
1. You’re mapping or reducing some dataset
2. Your iteration logic does not branch a lot
3. You can express your transformation logic using higher order functions (e.g. mapping a reduction operation across a multidimensional array)
Some domains have a log of this style of work—finance comes to mind—others do not. I suspect this is why I’ve personally seen a lot more of Clojure in finance circles than I have in other industries.
Maybe hyperbole on the frequency, but not the condensation. I meant more along the lines of “most of the complicated code I write in Clojure is an order of magnitude more dense.” _Most_ of the code I write would be 1:1 or 1:2 with other languages, it I don’t think it’s the type of code OP was referring to.
The 1:20+ is definitely not hyperbole though. Using transducers to stream lazy reductions of nested sequences; using case, cond-> and condp->; anywhere where you can lean on the clojure.core library. I don’t know how to give specific examples without giving a whole blog post of context, but 4 or 5 examples from the past year spring to mind.
It’s also often the case that optimizing my clojure code results in a significant reduction of lines of code, whereas optimizing Python code always resulted in an explosion of LoC
Personally I find Python particularly egregious. No map/filter/reduce, black formatting, no safe nested property access. File length was genuinely one of the reasons I stopped using it. The ratio would not be so high with some languages, ie JavaScript
Even with Elixir though, many solutions require 5-10 times the amount of lines for the same thing thing in Clojure. I just converted two functions yesterday that were 6 & 12 lines respectively in Clojure, and they are both 2 pages in Elixir (and would have been much longer in Python)
15 replies →
That's great, and I agree, but nobody really cares is the problem. They don't care about brevity and LISP is a really hard sell outside of those who "get it."
You need a REPL to truly read Clojure code. Could be a weakness or could be a strength. In my day to day work I consider a strength since I’m working at the REPL the whole day anyways
It's not difficult to read once you get writing it. My problem was getting other developers on board with it, which, ultimately, I failed at.